Mantid
Loading...
Searching...
No Matches
Rules.cpp
Go to the documentation of this file.
1// Mantid Repository : https://github.com/mantidproject/mantid
2//
3// Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI,
4// NScD Oak Ridge National Laboratory, European Spallation Source,
5// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
6// SPDX - License - Identifier: GPL - 3.0 +
7#include <algorithm>
8#include <cmath>
9#include <complex>
10#include <fstream>
11#include <iomanip>
12#include <iterator>
13#include <list>
14#include <map>
15#include <sstream>
16#include <stack>
17#include <string>
18#include <vector>
19
25#include "MantidKernel/Logger.h"
26#include "MantidKernel/Matrix.h"
27#include "MantidKernel/V3D.h"
28
29namespace Mantid::Geometry {
30
31namespace {
32Kernel::Logger logger("Rules");
33}
34
35int Rule::addToKey(std::vector<int> &AV, const int passN)
46{
47 for (int i = 0; i < static_cast<int>(AV.size()); i++) {
48 if (passN != i) {
49 if (AV[i] == 1)
50 AV[i] = 0;
51 else
52 return i + 1;
53 }
54 }
55 return -1;
56}
57
58int Rule::removeComplementary(std::unique_ptr<Rule> &TopRule)
70{
71 // Search down the rule until we get to common
72 // group. Once we have found a common type
73 // apply simple
74
75 if (TopRule->type() == 0) // One element tree (just return)
76 return 0;
77
78 int active(1); // active units
79
80 Rule *tmpA, *tmpB, *tmpC; // need three to play
81 DTriple<Rule *, int, Rule *> TreeComp; // Storage for top of stack
82
83 while (active) {
84 active = 0;
85 std::stack<DTriple<Rule *, int, Rule *>> TreeLine; // Tree stack of rules
86 TreeLine.push(DTriple<Rule *, int, Rule *>(nullptr, 0, TopRule.get()));
87
88 while (!active && !TreeLine.empty()) // need to exit on active
89 {
90 TreeComp = TreeLine.top();
91 TreeLine.pop();
92 // get first rule off tree
93 tmpA = TreeComp.third;
94
95 if (!tmpA->commonType()) // Not a common type, then we must get branches
96 {
97 tmpB = tmpA->leaf(0); // get leaves (two of)
98 tmpC = tmpA->leaf(1);
99 if (tmpB)
100 TreeLine.push(DTriple<Rule *, int, Rule *>(tmpA, 0, tmpB));
101 if (tmpC)
102 TreeLine.push(DTriple<Rule *, int, Rule *>(tmpA, 1, tmpC));
103 } else // Got something to simplify :-)
104 {
105 // In the simplification we don't need
106 // to add anything to the tree.
107 // This call the appropiate intersection/Union
108 // TrueCount 1 is a simple simplification
109 // -1 alway true
110 // -2 alway false
111 const int tcount(tmpA->simplify());
112
113 if (tcount == 1) // Deep simplification
114 {
115 active = 1;
116 } else if (tcount == -1) // replacement simplification
117 {
118 if (TreeComp.first) {
119 TreeComp.first = tmpA->leaf(0);
120 // delete tmpA
121 tmpA->setLeaf(nullptr, 0);
122 Rule *parentOfA = tmpA->getParent();
123 if (parentOfA) {
124 int leafNumber = parentOfA->findLeaf(tmpA);
125 parentOfA->setLeaf(nullptr, leafNumber);
126 }
127 }
128 }
129 }
130 }
131 }
132 return 1;
133}
134
135int Rule::makeCNFcopy(std::unique_ptr<Rule> &TopRule)
151{
152 // Start at top to tree to find an instance
153 // an intersection with stuff below.
154
155 int count(0); // Number of changes made
156 int active(1); // Do we still have to use
157 Rule *tmpA, *tmpB, *tmpC; // need three to play
158 DTriple<Rule *, int, Rule *> TreeComp; // Storage for top of stack
159
160 /*
161 The process works by below value deletion:
162 This is when the tree is modified at a particular
163 point, each member of the tree below the modification
164 point is deleted and the modification point is
165 replaced with a new version (normally a cloned copy).
166 This is fine for small items (eg here the memory footprint
167 is only 24 bytes, but not acceptable for bigger items.
168 The two layer insertion (which could be done) is more
169 complex but better proformance is possible.
170 */
171
172 while (active) {
173 active = 0;
174 count++;
175 // This stack takes a Different Triple < Parent, leaf, Child >
176 // We need to store the parent so that when we change the tree
177 // of a particular object. The integer records which side
178 // of the branch the tree object came from 0 == LHS 1==RHS.
179
180 std::stack<DTriple<Rule *, int, Rule *>> TreeLine; // Tree stack of rules
181
182 // Start by putting the top item on the Tree Stack.
183 // Note that it doesn't have a parent.
184 TreeLine.push(DTriple<Rule *, int, Rule *>(nullptr, 0, TopRule.get()));
185
186 // Exit condition is that nothing changed last time
187 // or the tree is Empty.
188
189 while (!active && !TreeLine.empty()) {
190 // Ok get and remove the top item from the stack.
191 TreeComp = TreeLine.top();
192 TreeLine.pop();
193
194 // Get the item. (not its parent)
195 tmpA = TreeComp.third; // get base item
196 // Now it might be a Union or Intersection
197 // so we need to get is branches.
198 // If it is a surface item then it will not have
199 // branches and thus tmpB and tmpC will == 0
200 tmpB = tmpA->leaf(0); // get leaves (two of)
201 tmpC = tmpA->leaf(1);
202
203 // If either then we need to put copies on the stack
204 // for later consideration.
205 // tmpA is the parent, since it is the leaves of tmpA the
206 // are written into tmpB and tmpC
207 if (tmpB)
208 TreeLine.push(DTriple<Rule *, int, Rule *>(tmpA, 0, tmpB));
209 if (tmpC)
210 TreeLine.push(DTriple<Rule *, int, Rule *>(tmpA, 1, tmpC));
211
212 //
213 // Time to see if we can apply rule 4 (propositional calculus)
214 // to expand (a ^ b) v c to (a v c) ^ (b v c)
215 //
216 if (tmpA->type() == 1 && tmpB && tmpC) // it is an intersection otherwise no work to do
217 {
218 // require either the left or right to be unions.
219 if (tmpB->type() == -1 || tmpC->type() == -1) // this is a union expand....
220 {
221 std::unique_ptr<Rule> alpha, beta, gamma;
222 if (tmpB->type() == -1) // ok the LHS is a union. (a ^ b) v g ==> (a v g) ^ (b v g )
223 {
224 // Make copies of the Unions leaves (allowing for null union)
225 alpha = (tmpB->leaf(0)) ? tmpB->leaf(0)->clone() : nullptr;
226 beta = (tmpB->leaf(1)) ? tmpB->leaf(1)->clone() : nullptr;
227 gamma = tmpC->clone();
228 } else // RHS a v (b ^ g) ==> (a v b) ^ (a v g )
229 {
230 // Make copies of the Unions leaves (allowing for null union)
231 // Note :: alpha designated as beta , gamma plays the role of alpha
232 // in the RHS part of the above equation (allows common replace
233 // block below.
234 alpha = (tmpC->leaf(0)) ? tmpC->leaf(0)->clone() : nullptr;
235 beta = (tmpC->leaf(1)) ? tmpC->leaf(1)->clone() : nullptr;
236 gamma = tmpB->clone();
237 }
238 // Have bit to replace
239
240 // Note:: no part of this can be memory copy
241 // hence we have to play games with a second
242 // gamma->clone()
243 std::unique_ptr<Rule> tmp1 = std::make_unique<Intersection>(std::move(alpha), gamma->clone());
244 std::unique_ptr<Rule> tmp2 = std::make_unique<Intersection>(std::move(beta), std::move(gamma));
245 std::unique_ptr<Rule> partReplace = std::make_unique<Union>(std::move(tmp1), std::move(tmp2));
246 //
247 // General replacement
248 //
249 if (TreeComp.first) // Not the top rule (so replace parents leaf)
250 TreeComp.first->setLeaf(std::move(partReplace), TreeComp.second);
251 else
252 // It is the top rule therefore, replace the toprule
253 TopRule = std::move(partReplace);
254
255 // Now we have to go back to the begining again and start again.
256 active = 1; // Exit loop
257 }
258 }
259 }
260 }
261 return count - 1; // return number of changes
262}
263
264int Rule::makeCNF(std::unique_ptr<Rule> &TopRule)
282{
283 // Start at top to tree to find an instance
284 // an intersection with stuff below.
285
286 if (!TopRule)
287 return 0;
288
289 TopRule->makeParents();
290 int count(0); // Number of changes made
291 int active(1); // Do we still have to use
292 Rule *tmpA, *tmpB, *tmpC; // need three to play
293
294 while (active) {
295 active = 0;
296 count++;
297 std::stack<Rule *> TreeLine; // Tree stack of rules
298
299 // Start by putting the top item on the Tree Stack.
300 // Note that it doesn't have a parent.
301 TreeLine.push(TopRule.get());
302
303 // Exit condition is that nothing changed last time
304 // or the tree is Empty.
305 if (!TopRule->checkParents())
306 logger.debug() << "Parents False\n";
307 while (!active && !TreeLine.empty()) {
308 // Ok get and remvoe the top item from the stack.
309 tmpA = TreeLine.top();
310 TreeLine.pop();
311
312 // Now it might be a Union or Intersection
313 // so we need to get is branches.
314
315 tmpB = tmpA->leaf(0); // get leaves (two of)
316 tmpC = tmpA->leaf(1);
317
318 if (tmpB)
319 TreeLine.push(tmpB);
320 if (tmpC)
321 TreeLine.push(tmpC);
322
323 //
324 // Time to see if we can apply rule 4 (propositional calculus)
325 // to expand (a ^ b) v c to (a v c) ^ (b v c)
326 //
327 if (tmpA->type() == 1 && tmpB && tmpC) // it is an intersection otherwise no work to do
328 {
329 // require either the left or right to be unions.
330 if (tmpB->type() == -1 || tmpC->type() == -1) // this is a union expand....
331 {
332 std::unique_ptr<Rule> alpha, beta, gamma; // Uobj to be deleted
333 if (tmpB->type() == -1) // ok the LHS is a union. (a ^ b) v g ==> (a v g) ^ (b v g )
334 {
335 // Make copies of the Unions leaves (allowing for null union)
336 alpha = tmpB->leaf(0)->clone();
337 beta = tmpB->leaf(1)->clone();
338 gamma = tmpC->clone();
339 } else // RHS a v (b ^ g) ==> (a v b) ^ (a v g )
340 {
341 // Make copies of the Unions leaves (allowing for null union)
342 // Note :: alpha designated as beta , gamma plays the role of alpha
343 // in the RHS part of the above equation (allows common replace
344 // block below.
345 alpha = tmpC->leaf(0)->clone();
346 beta = tmpC->leaf(1)->clone();
347 gamma = tmpB->clone();
348 }
349 // Have bit to replace
350
351 // Note:: no part of this can be memory copy
352 // hence we have to play games with a second
353 // gamma->clone()
354 std::unique_ptr<Rule> tmp1 = std::make_unique<Intersection>(std::move(alpha), gamma->clone());
355 std::unique_ptr<Rule> tmp2 = std::make_unique<Intersection>(std::move(beta), std::move(gamma));
356 std::unique_ptr<Rule> partReplace = std::make_unique<Union>(std::move(tmp1), std::move(tmp2));
357 //
358 // General replacement
359 //
360 Rule *Pnt = tmpA->getParent(); // parent
361 if (Pnt) // Not the top rule (so replace parents leaf)
362 {
363 const int leafN = Pnt->findLeaf(tmpA);
364 Pnt->setLeaf(std::move(partReplace), leafN);
365 } else
366 TopRule = std::move(partReplace);
367 // Now we have to go back to the begining again and start again.
368 active = 1; // Exit loop
369 }
370 }
371 }
372 }
373 return count - 1; // return number of changes
374}
375
376int Rule::removeItem(std::unique_ptr<Rule> &TRule, const int SurfN)
385{
386 int cnt(0);
387 Rule *Ptr = TRule->findKey(SurfN);
388 while (Ptr) {
389 Rule *LevelOne = Ptr->getParent(); // Must work
390 Rule *LevelTwo = (LevelOne) ? LevelOne->getParent() : nullptr;
391
392 if (LevelTwo)
393 {
394 // Decide which of the pairs is to be copied
395 const Rule *PObj = (LevelOne->leaf(0) != Ptr) ? LevelOne->leaf(0) : LevelOne->leaf(1);
396 //
397 const int side = (LevelTwo->leaf(0) != LevelOne) ? 1 : 0;
398 LevelTwo->setLeaf(PObj->clone(), side);
399 } else if (LevelOne) // LevelOne is the top rule
400 {
401 // Decide which of the pairs is to be copied
402 Rule *PObj = (LevelOne->leaf(0) != Ptr) ? LevelOne->leaf(0) : LevelOne->leaf(1);
403
404 PObj->setParent(nullptr);
405 TRule = PObj->clone();
406 } else // Basic surf object
407 {
408 auto *SX = dynamic_cast<SurfPoint *>(Ptr);
409 if (!SX) {
410 throw std::logic_error("Failed to cast Rule object to SurfPoint");
411 }
412 SX->setKeyN(0);
413 SX->setKey(std::shared_ptr<Surface>());
414 return cnt + 1;
415 }
416 Ptr = TRule->findKey(SurfN);
417 cnt++;
418 }
419 return cnt;
420}
421
423 : Parent(nullptr)
427{}
428
429Rule::Rule(const Rule & /*unused*/)
430 : Parent(nullptr)
435{}
436
438 : Parent(A)
444{}
445
446// cppcheck-suppress operatorEqVarError
447Rule &Rule::operator=(const Rule & /*unused*/)
454{
455 return *this;
456}
457
463{
464 Parent = A;
465}
466
472{
473 return Parent;
474}
475
481{
482 std::stack<Rule *> Tree;
483 Tree.push(this);
484 while (!Tree.empty()) {
485 Rule *Ptmp = Tree.top();
486 Tree.pop();
487
488 if (Ptmp) {
489 for (int i = 0; i < 2; i++) {
490 Rule *tmpB = Ptmp->leaf(i);
491 if (tmpB) {
492 tmpB->setParent(Ptmp);
493 Tree.push(tmpB);
494 }
495 }
496 }
497 }
498}
499
507{
508 std::stack<const Rule *> Tree;
509 Tree.push(this);
510 while (!Tree.empty()) {
511 const Rule *Ptmp = Tree.top();
512 Tree.pop();
513
514 if (Ptmp) {
515 for (int i = 0; i < 2; i++) {
516 const Rule *tmpB = Ptmp->leaf(i);
517 if (tmpB) {
518 if (tmpB->getParent() != Ptmp)
519 return 0;
520 }
521 }
522 }
523 }
524 return 1;
525}
526
535{
536 // initial type
537 const int rtype = this->type(); // note the dereference to get non-common comonents
538 if (!rtype)
539 return 0;
540 // now this must be an intersection or a Union
541 std::stack<const Rule *> Tree;
542 Tree.push(this->leaf(0));
543 Tree.push(this->leaf(1));
544 while (!Tree.empty()) {
545 const Rule *tmpA = Tree.top();
546 Tree.pop();
547 if (tmpA) {
548 if (tmpA->type() == -rtype) // other type return void
549 return 0;
550 const Rule *tmpB = tmpA->leaf(0);
551 const Rule *tmpC = tmpA->leaf(1);
552 if (tmpB)
553 Tree.push(tmpB);
554 if (tmpC)
555 Tree.push(tmpC);
556 }
557 }
558 return rtype;
559}
560
561int Rule::substituteSurf(const int SurfN, const int newSurfN, const std::shared_ptr<Surface> &SPtr)
569{
570 int cnt(0);
571 auto *Ptr = dynamic_cast<SurfPoint *>(findKey(SurfN));
572 while (Ptr) {
573 Ptr->setKeyN(Ptr->getSign() * newSurfN);
574 Ptr->setKey(SPtr);
575 cnt++;
576 // get next key
577 Ptr = dynamic_cast<SurfPoint *>(findKey(SurfN));
578 }
579 return cnt;
580}
581
582int Rule::getKeyList(std::vector<int> &IList) const
589{
590 IList.clear();
591 std::stack<const Rule *> TreeLine;
592 TreeLine.push(this);
593 while (!TreeLine.empty()) {
594 const Rule *tmpA = TreeLine.top();
595 TreeLine.pop();
596 const Rule *tmpB = tmpA->leaf(0);
597 const Rule *tmpC = tmpA->leaf(1);
598 if (tmpB || tmpC) {
599 if (tmpB)
600 TreeLine.push(tmpB);
601 if (tmpC)
602 TreeLine.push(tmpC);
603 } else {
604 const auto *SurX = dynamic_cast<const SurfPoint *>(tmpA);
605 if (SurX)
606 IList.emplace_back(SurX->getKeyN());
607 else {
608 logger.error() << "Error with surface List\n";
609 return static_cast<int>(IList.size());
610 }
611 }
612 }
613 std::sort(IList.begin(), IList.end());
614 auto px = std::unique(IList.begin(), IList.end());
615 IList.erase(px, IList.end());
616 return static_cast<int>(IList.size());
617}
618
626{
627 std::map<int, int> Base; // map of key names + test value (initially 1)
628 std::vector<int> baseVal;
629 std::vector<int> baseKeys;
630 std::vector<int> deadKeys;
631 // collect base keys and populate the cells
632 getKeyList(baseKeys);
633 std::vector<int>::const_iterator xv;
634 for (xv = baseKeys.begin(); xv != baseKeys.end(); ++xv) {
635 baseVal.emplace_back(0);
636 Base[(*xv)] = 1;
637 }
638
639 // For each key :: check if the Rule is equal for both cases 0 + 1
640 // then loop through all combinations of the map to determine validity
641 // This function is not optimised since the tree can be trimmed
642 // if the test item is not in a branch.
643 for (unsigned int TKey = 0; TKey < baseKeys.size(); TKey++) {
644 // INITIALISE STUFF
645 int valueTrue(1), valueFalse(1);
646 int keyChange = 0;
647 int targetKey = baseKeys[TKey];
648 for (unsigned int i = 0; i < baseVal.size(); i++) {
649 baseVal[i] = 0;
650 Base[baseKeys[i]] = 0;
651 }
652
653 // CHECK EACH KEY IN TURN
654 while (valueTrue == valueFalse || keyChange >= 0) {
655 // Zero value
656 Base[baseKeys[targetKey]] = 0;
657 valueFalse = isValid(Base);
658
659 // True value
660 Base[baseKeys[targetKey]] = 1;
661 valueTrue = isValid(Base);
662
663 // Put everything back
664 if (valueTrue == valueFalse) {
665 keyChange = addToKey(baseVal, TKey); // note pass index not key
666 for (int ic = 0; ic < keyChange; ic++)
667 Base[baseKeys[ic]] = baseVal[ic];
668 }
669 }
670 deadKeys.emplace_back(targetKey);
671 }
672 return static_cast<int>(deadKeys.size());
673}
674
675} // namespace Mantid::Geometry
int count
counter
Definition Matrix.cpp:37
Triple of three different things.
Definition Triple.h:53
S second
Second item.
Definition Triple.h:56
T third
Third item.
Definition Triple.h:57
F first
First item.
Definition Triple.h:55
Object generation rule tree.
Definition Rules.h:33
int Eliminate()
elimination not written
Definition Rules.cpp:619
Rule * getParent() const
Returns the parent object.
Definition Rules.cpp:467
void setParent(Rule *)
Sets the parent object (not check for A==this)
Definition Rules.cpp:458
virtual Rule * leaf(const int=0) const
No leaf for a base rule.
Definition Rules.h:59
std::unique_ptr< Rule > clone() const
Definition Rules.h:54
int commonType() const
Gets a common type.
Definition Rules.cpp:527
Rule & operator=(const Rule &)
Assignment operator= does not set parent as Rules are cloned.
Definition Rules.cpp:447
void makeParents()
This is initialisation code that populates all the parents in the rule tree.
Definition Rules.cpp:476
int getKeyList(std::vector< int > &) const
Generate the key list given an insertion type object.
Definition Rules.cpp:582
static int makeCNF(std::unique_ptr< Rule > &)
Make Rule into a CNF format.
Definition Rules.cpp:264
virtual Rule * findKey(const int)=0
Abstract key find.
static int addToKey(std::vector< int > &AV, const int passN=-1)
Static function :: Given a vector AV increase the number from lowest to highest in an iterative count...
Definition Rules.cpp:35
static int makeCNFcopy(std::unique_ptr< Rule > &)
Make Rule into a CNF format (slow)
Definition Rules.cpp:135
virtual int findLeaf(const Rule *) const =0
Abstract find.
virtual void setLeaf(std::unique_ptr< Rule >, const int=0)=0
Abstract set.
static int removeItem(std::unique_ptr< Rule > &TRule, const int SurfN)
Given an item as a surface name, remove the surface from the Rule tree.
Definition Rules.cpp:376
int substituteSurf(const int SurfN, const int newSurfN, const std::shared_ptr< Surface > &SPtr)
Substitues a surface item if within a rule.
Definition Rules.cpp:561
Rule()
Standard Constructor.
Definition Rules.cpp:422
Rule * Parent
Parent object (for tree)
Definition Rules.h:35
virtual bool isValid(const Kernel::V3D &) const =0
Abstract: The point is within the object.
int checkParents() const
Debug test for parents.
Definition Rules.cpp:500
static int removeComplementary(std::unique_ptr< Rule > &)
NOT WORKING.
Definition Rules.cpp:58
virtual int simplify()=0
Abstract: Can the rule be simplified.
virtual int type() const
Null rule.
Definition Rules.h:73
Surface leaf node.
Definition Rules.h:213
void setKeyN(const int Ky)
set keyNumber