Salome HOME
Algorithm of level of parallelism has been extended to more complex cases.
[modules/yacs.git] / src / engine / AbstractPoint.cxx
1 // Copyright (C) 2015-2019  CEA/DEN, EDF R&D
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19
20 #include "AbstractPoint.hxx"
21 #include "LinkedBlocPoint.hxx"
22 #include "ForkBlocPoint.hxx"
23 #include "NotSimpleCasePoint.hxx"
24 #include "SetOfPoints.hxx"
25 #include "BagPoint.hxx"
26 #include "ElementaryPoint.hxx"
27 #include "Node.hxx"
28 #include "Bloc.hxx"
29
30 #include <algorithm>
31
32 using namespace YACS::ENGINE;
33
34 AbstractPoint::~AbstractPoint()
35 {
36 }
37
38 AbstractPoint *AbstractPoint::getGodFather()
39 {
40   if(_father==0)
41     return this;
42   else
43     return _father->getGodFather();
44 }
45
46 bool AbstractPoint::isBegin()
47 {
48   Node *beg(getFirstNode());
49   InGate *ing(beg->getInGate());
50   return ing->getBackLinks().empty();
51 }
52
53 bool AbstractPoint::isLast()
54 {
55   Node *endd(getLastNode());
56   OutGate *oug(endd->getOutGate());
57   return oug->edSetInGate().empty();
58 }
59
60 bool AbstractPoint::isSimplyLinkedBeforeAfter(BlocPoint *sop)
61 {
62   Node *beg(getFirstNode()),*endd(getLastNode());
63   return isSimplyLinkedBefore(sop,beg) && isSimplyLinkedAfter(sop,endd);
64 }
65
66 bool AbstractPoint::isSimplyLinkedAfterNullBefore(BlocPoint *sop)
67 {
68   Node *beg(getFirstNode()),*endd(getLastNode());
69   return IsNoLinksBefore(beg) && isSimplyLinkedAfter(sop,endd);
70 }
71
72 bool AbstractPoint::isSimplyLinkedBeforeNullAfter(BlocPoint *sop)
73 {
74   Node *beg(getFirstNode()),*endd(getLastNode());
75   return IsNoLinksAfter(endd) && isSimplyLinkedBefore(sop,beg);
76 }
77
78 /*!
79  * precondition : isSimplyLinkedBeforeAfter must return true on \a this.
80  */
81 LinkedBlocPoint *AbstractPoint::tryAsLink(BlocPoint *sop)
82 {
83   Node *bb(getFirstNode()),*ee(getLastNode());
84   std::list<AbstractPoint *> l; l.push_back(this);
85   AbstractPoint *cur2(0);
86   //
87   cur2=sop->getNodeB4(bb);
88   while(cur2)
89     {
90       if(dynamic_cast<NotSimpleCasePoint *>(cur2))
91         continue;
92       Node *cur3(cur2->getFirstNode());
93       if(cur2->isSimplyLinkedBeforeAfter(sop))
94         {
95           l.push_front(cur2);
96           cur2=sop->getNodeB4(cur3);
97           continue;
98         }
99       else if(IsGatherB4Ext(cur3) && isSimplyLinkedAfter(sop,cur2->getLastNode()))
100         {
101           l.push_front(cur2);
102           break;
103         }
104       else
105         break;
106     }
107   //
108   cur2=sop->getNodeAfter(ee);
109   while(cur2)
110     {
111       if(dynamic_cast<NotSimpleCasePoint *>(cur2))
112         continue;
113       Node *cur3(cur2->getLastNode());
114       if(cur2->isSimplyLinkedBeforeAfter(sop))
115         {
116           l.push_back(cur2);
117           cur2=sop->getNodeAfter(cur3);
118           continue;
119         }
120       else if(IsScatterAfterExt(cur3) && isSimplyLinkedBefore(sop,cur2->getFirstNode()))
121         {
122           l.push_back(cur2);
123           break;
124         }
125       else
126         break;
127     }
128   if(l.size()>1)
129     {
130       return new LinkedBlocPoint(l,getFather());
131     }
132   else
133     return nullptr;
134 }
135
136 /*!
137  * precondition : isSimplyLinkedBeforeAfter must return true on \a this.
138  */
139 ForkBlocPoint *AbstractPoint::tryAsFork(BlocPoint *sop)
140 {
141   Node *bb(GetNodeB4(getFirstNode())),*ee(GetNodeAfter(getLastNode()));
142   AbstractPoint *bb2(sop->findPointWithNode(bb)),*ee2(sop->findPointWithNode(ee));
143   //
144   const std::list<AbstractPoint *>& lp(sop->getListOfPoints());
145   std::list<AbstractPoint *> l; l.push_back(this);
146   for(std::list<AbstractPoint *>::const_iterator it=lp.begin();it!=lp.end();it++)
147     {
148       if(*it==this)
149         continue;
150       if(dynamic_cast<NotSimpleCasePoint *>(*it))
151         continue;
152       Node *curFirst((*it)->getFirstNode()),*curEnd((*it)->getLastNode());
153       if(!IsSimplyLinkedBeforeExt(curFirst) || !IsSimplyLinkedAfterExt(curEnd))
154         continue;
155       Node *curbb(GetNodeB4(curFirst)),*curee(GetNodeAfter(curEnd));
156       AbstractPoint *bb3(sop->findPointWithNode(curbb)),*ee3(sop->findPointWithNode(curee));
157       if(bb2==bb3 && ee2==ee3)
158         l.push_back(*it);
159     }
160   if(l.size()>1)
161     {
162       return new ForkBlocPoint(l,getFather());
163     }
164   else
165     return nullptr;
166 }
167
168 ForkBlocPoint *AbstractPoint::tryAsForkBis(BlocPoint *sop)
169 {
170   Node *bb(GetNodeB4(getFirstNode())),*ee(GetNodeAfter(getLastNode()));
171   AbstractPoint *ee2(sop->findPointWithNode(ee));
172   //
173   const std::list<AbstractPoint *>& lp(sop->getListOfPoints());
174   std::list<AbstractPoint *> l; l.push_back(this);
175   for(std::list<AbstractPoint *>::const_iterator it=lp.begin();it!=lp.end();it++)
176     {
177       if(*it==this)
178         continue;
179       if(dynamic_cast<NotSimpleCasePoint *>(*it))
180         continue;
181       Node *curFirst((*it)->getFirstNode()),*curEnd((*it)->getLastNode());
182       if(!IsNoLinksBefore(curFirst) || !IsSimplyLinkedAfterExt(curEnd))
183         continue;
184       Node *curee(GetNodeAfter(curEnd));
185       AbstractPoint *ee3(sop->findPointWithNode(curee));
186       if(ee2==ee3)
187         l.push_back(*it);
188     }
189   if(l.size()>1)
190     {
191       return new ForkBlocPoint(l,getFather());
192     }
193   else
194     return nullptr;
195 }
196
197 ForkBlocPoint *AbstractPoint::tryAsForkTer(BlocPoint *sop)
198 {
199   Node *bb(GetNodeB4(getFirstNode())),*ee(GetNodeAfter(getLastNode()));
200   AbstractPoint *bb2(sop->findPointWithNode(bb));
201   //
202   const std::list<AbstractPoint *>& lp(sop->getListOfPoints());
203   std::list<AbstractPoint *> l; l.push_back(this);
204   for(std::list<AbstractPoint *>::const_iterator it=lp.begin();it!=lp.end();it++)
205     {
206       if(*it==this)
207         continue;
208       if(dynamic_cast<NotSimpleCasePoint *>(*it))
209         continue;
210       Node *curFirst((*it)->getFirstNode()),*curEnd((*it)->getLastNode());
211       if(!IsSimplyLinkedBeforeExt(curFirst) || !IsNoLinksAfter(curEnd))
212         continue;
213       Node *curbb(GetNodeB4(curFirst));
214       AbstractPoint *bb3(sop->findPointWithNode(curbb));
215       if(bb2==bb3)
216         l.push_back(*it);
217     }
218   if(l.size()>1)
219     {
220       return new ForkBlocPoint(l,getFather());
221     }
222   else
223     return nullptr;
224 }
225
226 #include <iostream>
227
228 class Visitor1 : public YACS::ENGINE::PointVisitor
229 {
230 public:
231   Visitor1(std::map< std::string, std::tuple< ElementaryPoint *, Node *, std::shared_ptr<Bloc> > > *m):_m(m) { }
232   void beginForkBlocPoint(ForkBlocPoint *pt) { }
233   void endForkBlocPoint(ForkBlocPoint *pt) { }
234   void beginLinkedBlocPoint(LinkedBlocPoint *pt) { }
235   void endLinkedBlocPoint(LinkedBlocPoint *pt) { }
236   void beginElementaryPoint(ElementaryPoint *pt)
237   {
238     std::string nodeName(pt->getNodeName());
239     auto it(_m->find(nodeName));
240     if(it==_m->end())
241       {
242         (*_m)[nodeName] = std::tuple< ElementaryPoint *, Node *, std::shared_ptr<Bloc> >(pt,pt->getNode(),std::make_shared<Bloc>(nodeName));
243       }
244   }
245   void endElementaryPoint(ElementaryPoint *pt) { }
246   void beginNotSimpleCasePoint(NotSimpleCasePoint *pt) { }
247   void endNotSimpleCasePoint(NotSimpleCasePoint *pt) { }
248 private:
249   std::map< std::string, std::tuple< ElementaryPoint *, Node *, std::shared_ptr<Bloc> > > *_m;
250 };
251
252 /*!
253  * Feed m with all ElementaryPoints inside \a ptToBeRewired.
254  */
255 void AbstractPoint::FeedData(AbstractPoint *ptToBeRewired, std::map< std::string, std::tuple< ElementaryPoint *, Node *, std::shared_ptr<Bloc> > > *m)
256 {
257   Visitor1 vis(m);
258   ptToBeRewired->accept(&vis);
259 }
260
261 /*!
262  * Feed m with all ElementaryPoints inside \a ptsToBeRewired.
263  */
264 void AbstractPoint::FeedData(const std::list<AbstractPoint *>& ptsToBeRewired, std::map< std::string, std::tuple< ElementaryPoint *, Node *, std::shared_ptr<Bloc> > > *m)
265 {
266   for(auto it : ptsToBeRewired)
267     FeedData(it,m);
268 }
269
270 bool containsPtsToKill(const std::vector<AbstractPoint *>& ptsToKill, Node *node)
271 {
272   for(auto it : ptsToKill)
273     if(it->contains(node))
274       return true;
275   return false;
276 }
277
278 /*!
279  * This method go throw all ElementaryPoints of \a m. 
280  * For each ElementaryPoint change the Node instance underneath. And then create links between those new Node by excluding all links going whose destination :
281  * - is inside \a ptToKill
282  * - is not refered by \a m
283  * 
284  * CF links of old nodes are NOT touched for unrewire phase.
285  * Typically all ElementaryPoints inside \a ptToKill are NOT into \a m.
286  */
287 void AbstractPoint::Rewire(const std::vector<AbstractPoint *>& ptsToKill, std::map< std::string, std::tuple< ElementaryPoint *, Node *, std::shared_ptr<Bloc> > > *m)
288 {
289   for(auto it : *m)
290     {
291       ElementaryPoint *pt(std::get<0>(it.second));
292       Node *node(std::get<1>(it.second));
293       auto newNode(std::get<2>(it.second).get());
294       pt->setNode(newNode);
295     }
296   for(auto it : *m)
297     {
298       ElementaryPoint *pt(std::get<0>(it.second));
299       Node *node(std::get<1>(it.second));
300       auto newNode(std::get<2>(it.second).get());
301       if(containsPtsToKill(ptsToKill,newNode))
302         continue;
303       for(auto it2 : node->getOutGate()->edSetInGate())
304         {
305           Node *nodeFwd(it2->getNode());
306           std::string nodeFwdName(nodeFwd->getName());
307           auto it3(m->find(nodeFwdName));
308           if(it3!=m->end())
309             {
310               Node *nodeFwdNew = std::get<2>(it3->second).get();
311               if(!containsPtsToKill(ptsToKill,newNode))
312                 {
313                   newNode->getOutGate()->edAddInGate(nodeFwdNew->getInGate());
314                 }
315               //else
316               // node after nodeFwd is not in m fall into \a ptToKill
317               // -> ignore link.
318             }
319           //else
320           // node after nodeFwd is not in m. Typically because nodeFwd has not been put in m
321           // concretely : do not link incoming links to Node * inside ptToKill
322         }
323     }
324 }
325
326 /*!
327  * Unrewire consists into replacing newly created nodes into old one in ElementaryPoints contained in m.
328  * As CF links of old ENGINE::Node * has not be touched the CF graph is the same.
329  */
330 void AbstractPoint::UnRewire(std::map< std::string, std::tuple< ElementaryPoint *, Node *, std::shared_ptr<Bloc> > >& m)
331 {
332   for(auto it : m)
333     {
334       ElementaryPoint *pt(std::get<0>(it.second));
335       Node *node(std::get<1>(it.second));
336       pt->setNode(node);
337     }
338 }
339
340 void AbstractPoint::Display(std::map< std::string, std::tuple< ElementaryPoint *, Node *, std::shared_ptr<Bloc> > > *m)
341 {
342   for(auto it : *m)
343     {
344       ElementaryPoint *pt(std::get<0>(it.second));
345       auto newNode(pt->getNode());
346       for(auto it2 : newNode->getOutGate()->edSetInGate())
347         {
348           std::cerr << pt->getNodeName() << " -> " << it2->getNode()->getName() << " " << newNode->typeName() << std::endl;
349         }
350     }
351 }
352
353 /*!
354  * This methods tries to deal with \a sop that can t be considered as a composite of Link, Fork.
355  * 
356  * Do do so, this methods tries to exclude \a this from \a sop and then analyze if the graph can be decomposited into Links and Forks. If yes \a somethingDone is set to true and \a nodes is updated in consequence.
357  * 
358  * If the algorithm fails \a nodes are let untouched and \a somethingDone is let false.
359  *
360  */
361 void AbstractPoint::TryAsNotSimpleCase(AbstractPoint *father, const std::vector<AbstractPoint *>& ptsToKill, std::list<AbstractPoint *>& nodes, bool& somethingDone)
362 {
363   std::list<AbstractPoint *> lp2;
364   for(auto it : nodes)
365     {
366       if(std::find(ptsToKill.cbegin(),ptsToKill.cend(),it)==ptsToKill.cend())
367         lp2.push_back(it->deepCopy(nullptr));
368     }
369   BagPoint *tmp(new BagPoint(lp2,nullptr));
370   for(auto it : lp2)
371     it->setFather(tmp);
372   SetOfPoints sopTest(tmp);
373   std::map< std::string, std::tuple< ElementaryPoint *, Node *, std::shared_ptr<Bloc> > > m;
374   FeedData(tmp,&m);
375   Rewire(ptsToKill,&m);
376   try
377     {
378       sopTest.basicSimplify();
379     }
380   catch(YACS::Exception& ex)
381     {// By removing elements in ptsToKill from this impossible to have a classical case -> un rewire to rollback nodes state
382       UnRewire(m);
383       return ;
384     }
385   AbstractPoint *pt(sopTest.getUniqueAndReleaseIt());
386   pt->setFather(father);
387   UnRewire(m);
388   for(auto it : nodes)
389     if(std::find(ptsToKill.cbegin(),ptsToKill.cend(),it)==ptsToKill.cend())
390       delete it;
391   nodes.clear();
392   nodes.push_back(pt);
393   for(auto it : ptsToKill)
394     {
395       std::list<AbstractPoint *> l; l.push_back(it);
396       nodes.push_back( new NotSimpleCasePoint(l,father) );
397     }
398   somethingDone = true;
399 }
400
401 bool AbstractPoint::IsGatherB4Ext(Node *node)
402 {
403   InGate *ing(node->getInGate());
404   return ing->getBackLinks().size()!=1;
405 }
406
407 bool AbstractPoint::isSimplyLinkedAfter(BlocPoint *sop, Node *node)
408 {
409   OutGate *oug(node->getOutGate());
410   std::list<InGate *> ings(oug->edSetInGate());
411   if(ings.size()==1)
412     return true;
413   if(ings.size()==0)
414     return false;
415   AbstractPoint *dummy=0;
416   return IsCommonDirectSonOf(sop,ings,dummy);
417 }
418
419 bool AbstractPoint::IsSimplyLinkedAfterExt(Node *node)
420 {
421   OutGate *oug(node->getOutGate());
422   return oug->edSetInGate().size()<=1;
423 }
424
425 bool AbstractPoint::IsScatterAfterExt(Node *node)
426 {
427   OutGate *oug(node->getOutGate());
428   return oug->edSetInGate().size()!=1;
429 }
430
431 bool AbstractPoint::isSimplyLinkedBefore(BlocPoint *sop, Node *node)
432 {
433   InGate *ing(node->getInGate());
434   std::list<OutGate *> outgs(ing->getBackLinks());
435   if(outgs.size()==1)
436     return true;
437   if(outgs.size()==0)
438     return false;
439   AbstractPoint *dummy=0;
440   return IsCommonDirectSonOf(sop,outgs,dummy);
441 }
442
443 bool AbstractPoint::IsSimplyLinkedBeforeExt(Node *node)
444 {
445   InGate *ing(node->getInGate());
446   return ing->getBackLinks().size()<=1;
447 }
448
449 bool AbstractPoint::IsNoLinksBefore(Node *node)
450 {
451   InGate *ing(node->getInGate());
452   return ing->getBackLinks().size()==0;
453 }
454
455 bool AbstractPoint::IsNoLinksAfter(Node *node)
456 {
457   OutGate *oug(node->getOutGate());
458   return oug->edSetInGate().size()==0;
459 }
460
461 Node *AbstractPoint::GetNodeB4(Node *node)
462 {
463   InGate *ing(node->getInGate());
464   std::list<OutGate *> bl(ing->getBackLinks());
465   if(bl.size()>1)
466     throw Exception("AbstractPoint::GetNodeB4 : precond not OK !");
467   if(bl.size()==0)
468     return 0;
469   return bl.front()->getNode();
470 }
471
472 Node *AbstractPoint::GetNodeAfter(Node *node)
473 {
474   OutGate *oug(node->getOutGate());
475   std::list<InGate *> fl(oug->edSetInGate());
476   if(fl.size()>1)
477     throw Exception("AbstractPoint::GetNodeAfter : precond not OK !");
478   if(fl.size()==0)
479     return 0;
480   return (*fl.begin())->getNode();
481 }
482
483 AbstractPoint *AbstractPoint::GetDirectSonOf(AbstractPoint *refFather, AbstractPoint *sonOrLittleSon)
484 {
485   if(!sonOrLittleSon)
486     throw YACS::Exception("AbstractPoint::GetDirectSonOf : sonOrLittleSon is null !");
487   AbstractPoint *curFath(sonOrLittleSon->getFather()),*cur(sonOrLittleSon);
488   while(curFath && curFath!=refFather)
489     {
490       cur=curFath;
491       curFath=cur->getFather();
492     }
493   if(!curFath)
494     throw YACS::Exception("AbstractPoint::GetDirectSonOf : not in the same family !");
495   return cur;
496 }
497
498 bool AbstractPoint::IsCommonDirectSonOf(AbstractPoint *refFather, const std::list<OutGate *>& outgs, AbstractPoint *&ret)
499 {
500   if(outgs.size()<1)
501     throw YACS::Exception("AbstractPoint::GetCommonDirectSonOf1 : not enough !");
502   std::list<OutGate *>::const_iterator it(outgs.begin());
503   OutGate *ref(*(it++));
504   AbstractPoint *ref2(GetDirectSonOf(refFather,refFather->findPointWithNode(ref->getNode())));
505   for(;it!=outgs.end();it++)
506     {
507       if(!ref2->contains((*it)->getNode()))
508         return false;
509     }
510   ret=ref2;
511   return true;
512 }
513
514 bool AbstractPoint::IsCommonDirectSonOf(AbstractPoint *refFather, const std::list<InGate *>& ings, AbstractPoint *&ret)
515 {
516   if(ings.size()<1)
517     throw YACS::Exception("AbstractPoint::GetCommonDirectSonOf2 : not enough !");
518   std::list<InGate *>::const_iterator it(ings.begin());
519   InGate *ref(*(it++));
520   AbstractPoint *ref2(GetDirectSonOf(refFather,refFather->findPointWithNode(ref->getNode())));
521   for(;it!=ings.end();it++)
522     {
523       if(!ref2->contains((*it)->getNode()))
524         return false;
525     }
526   ret=ref2;
527   return true;
528 }