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 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
446Rule &Rule::operator=(const Rule & /*unused*/)
453{
454 return *this;
455}
456
462{
463 Parent = A;
464}
465
471{
472 return Parent;
473}
474
480{
481 std::stack<Rule *> Tree;
482 Tree.push(this);
483 while (!Tree.empty()) {
484 Rule *Ptmp = Tree.top();
485 Tree.pop();
486
487 if (Ptmp) {
488 for (int i = 0; i < 2; i++) {
489 Rule *tmpB = Ptmp->leaf(i);
490 if (tmpB) {
491 tmpB->setParent(Ptmp);
492 Tree.push(tmpB);
493 }
494 }
495 }
496 }
497}
498
506{
507 std::stack<const Rule *> Tree;
508 Tree.push(this);
509 while (!Tree.empty()) {
510 const Rule *Ptmp = Tree.top();
511 Tree.pop();
512
513 if (Ptmp) {
514 for (int i = 0; i < 2; i++) {
515 const Rule *tmpB = Ptmp->leaf(i);
516 if (tmpB) {
517 if (tmpB->getParent() != Ptmp)
518 return 0;
519 }
520 }
521 }
522 }
523 return 1;
524}
525
534{
535 // initial type
536 const int rtype = this->type(); // note the dereference to get non-common comonents
537 if (!rtype)
538 return 0;
539 // now this must be an intersection or a Union
540 std::stack<const Rule *> Tree;
541 Tree.push(this->leaf(0));
542 Tree.push(this->leaf(1));
543 while (!Tree.empty()) {
544 const Rule *tmpA = Tree.top();
545 Tree.pop();
546 if (tmpA) {
547 if (tmpA->type() == -rtype) // other type return void
548 return 0;
549 const Rule *tmpB = tmpA->leaf(0);
550 const Rule *tmpC = tmpA->leaf(1);
551 if (tmpB)
552 Tree.push(tmpB);
553 if (tmpC)
554 Tree.push(tmpC);
555 }
556 }
557 return rtype;
558}
559
560int Rule::substituteSurf(const int SurfN, const int newSurfN, const std::shared_ptr<Surface> &SPtr)
568{
569 int cnt(0);
570 auto *Ptr = dynamic_cast<SurfPoint *>(findKey(SurfN));
571 while (Ptr) {
572 Ptr->setKeyN(Ptr->getSign() * newSurfN);
573 Ptr->setKey(SPtr);
574 cnt++;
575 // get next key
576 Ptr = dynamic_cast<SurfPoint *>(findKey(SurfN));
577 }
578 return cnt;
579}
580
581int Rule::getKeyList(std::vector<int> &IList) const
588{
589 IList.clear();
590 std::stack<const Rule *> TreeLine;
591 TreeLine.push(this);
592 while (!TreeLine.empty()) {
593 const Rule *tmpA = TreeLine.top();
594 TreeLine.pop();
595 const Rule *tmpB = tmpA->leaf(0);
596 const Rule *tmpC = tmpA->leaf(1);
597 if (tmpB || tmpC) {
598 if (tmpB)
599 TreeLine.push(tmpB);
600 if (tmpC)
601 TreeLine.push(tmpC);
602 } else {
603 const auto *SurX = dynamic_cast<const SurfPoint *>(tmpA);
604 if (SurX)
605 IList.emplace_back(SurX->getKeyN());
606 else {
607 logger.error() << "Error with surface List\n";
608 return static_cast<int>(IList.size());
609 }
610 }
611 }
612 std::sort(IList.begin(), IList.end());
613 auto px = std::unique(IList.begin(), IList.end());
614 IList.erase(px, IList.end());
615 return static_cast<int>(IList.size());
616}
617
625{
626 std::map<int, int> Base; // map of key names + test value (initially 1)
627 std::vector<int> baseVal;
628 std::vector<int> baseKeys;
629 std::vector<int> deadKeys;
630 // collect base keys and populate the cells
631 getKeyList(baseKeys);
632 std::vector<int>::const_iterator xv;
633 for (xv = baseKeys.begin(); xv != baseKeys.end(); ++xv) {
634 baseVal.emplace_back(0);
635 Base[(*xv)] = 1;
636 }
637
638 // For each key :: check if the Rule is equal for both cases 0 + 1
639 // then loop through all combinations of the map to determine validity
640 // This function is not optimised since the tree can be trimmed
641 // if the test item is not in a branch.
642 for (unsigned int TKey = 0; TKey < baseKeys.size(); TKey++) {
643 // INITIALISE STUFF
644 int valueTrue(1), valueFalse(1);
645 int keyChange = 0;
646 int targetKey = baseKeys[TKey];
647 for (unsigned int i = 0; i < baseVal.size(); i++) {
648 baseVal[i] = 0;
649 Base[baseKeys[i]] = 0;
650 }
651
652 // CHECK EACH KEY IN TURN
653 while (valueTrue == valueFalse || keyChange >= 0) {
654 // Zero value
655 Base[baseKeys[targetKey]] = 0;
656 valueFalse = isValid(Base);
657
658 // True value
659 Base[baseKeys[targetKey]] = 1;
660 valueTrue = isValid(Base);
661
662 // Put everything back
663 if (valueTrue == valueFalse) {
664 keyChange = addToKey(baseVal, TKey); // note pass index not key
665 for (int ic = 0; ic < keyChange; ic++)
666 Base[baseKeys[ic]] = baseVal[ic];
667 }
668 }
669 if (keyChange < 0) // Success !!!!!
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:618
Rule * getParent() const
Returns the parent object.
Definition: Rules.cpp:466
void setParent(Rule *)
Sets the parent object (not check for A==this)
Definition: Rules.cpp:457
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:526
Rule & operator=(const Rule &)
Assignment operator= does not set parent as Rules are cloned.
Definition: Rules.cpp:446
void makeParents()
This is initialisation code that populates all the parents in the rule tree.
Definition: Rules.cpp:475
int getKeyList(std::vector< int > &) const
Generate the key list given an insertion type object.
Definition: Rules.cpp:581
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:560
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:499
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
Definition: RuleItems.cpp:742