Salome HOME
Optimized algo for PlayGround
[modules/yacs.git] / src / engine / PlayGround.cxx
1 // Copyright (C) 2006-2017  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 "PlayGround.hxx"
21 #include "Runtime.hxx"
22
23 #include <set>
24 #include <map>
25 #include <sstream>
26 #include <iomanip>
27 #include <numeric>
28 #include <algorithm>
29
30 using namespace YACS::ENGINE;
31
32
33 std::string PlayGround::printSelf() const
34 {
35   std::ostringstream oss;
36   std::size_t sz(0);
37   for(std::vector< std::pair<std::string,int> >::const_iterator it=_data.begin();it!=_data.end();it++)
38     sz=std::max(sz,(*it).first.length());
39   for(std::vector< std::pair<std::string,int> >::const_iterator it=_data.begin();it!=_data.end();it++)
40     {
41       oss << " - " << std::setw(10) << (*it).first << " : " << (*it).second << std::endl;
42     }
43   return oss.str();
44 }
45
46 void PlayGround::loadFromKernelCatalog()
47 {
48   Runtime *r(getRuntime());
49   if(!r)
50     throw Exception("PlayGround::loadFromKernelCatalog : no runtime  !");
51   std::vector< std::pair<std::string,int> > data(r->getCatalogOfComputeNodes());
52   setData(data);
53 }
54
55 void PlayGround::setData(const std::vector< std::pair<std::string,int> >& defOfRes)
56 {
57   _data=defOfRes;
58   checkCoherentInfo();
59 }
60
61 int PlayGround::getNumberOfCoresAvailable() const
62 {
63   int ret(0);
64   for(std::vector< std::pair<std::string,int> >::const_iterator it=_data.begin();it!=_data.end();it++)
65     ret+=(*it).second;
66   return ret;
67 }
68
69 int PlayGround::getMaxNumberOfContainersCanBeHostedWithoutOverlap(int nbCoresPerCont) const
70 {
71   if(nbCoresPerCont<1)
72     throw Exception("PlayGround::getMaxNumberOfContainersCanBeHostedWithoutOverlap : invalid nbCoresPerCont. Must be >=1 !");
73   int ret(0);
74   for(std::vector< std::pair<std::string,int> >::const_iterator it=_data.begin();it!=_data.end();it++)
75     ret+=(*it).second/nbCoresPerCont;
76   return ret;
77 }
78
79 std::vector<int> PlayGround::computeOffsets() const
80 {
81   std::size_t sz(_data.size()),i(0);
82   std::vector<int> ret(sz+1); ret[0]=0;
83   for(std::vector< std::pair<std::string,int> >::const_iterator it=_data.begin();it!=_data.end();it++,i++)
84     ret[i+1]=ret[i]+(*it).second;
85   return ret;
86 }
87
88 void PlayGround::checkCoherentInfo() const
89 {
90   std::set<std::string> s;
91   for(std::vector< std::pair<std::string,int> >::const_iterator it=_data.begin();it!=_data.end();it++)
92     {
93       s.insert((*it).first);
94       if((*it).second<0)
95         throw Exception("Presence of negative int value !");
96     }
97   if(s.size()!=_data.size())
98     throw Exception("host names entries must be different each other !");
99 }
100
101 std::vector<int> PlayGround::GetIdsMatching(const std::vector<bool>& bigArr, const std::vector<bool>& pat)
102 {
103   std::vector<int> ret;
104   std::size_t szp(pat.size());
105   std::size_t sz(bigArr.size()/szp);
106   for(std::size_t i=0;i<sz;i++)
107     {
108       std::vector<bool> t(bigArr.begin()+i*szp,bigArr.begin()+(i+1)*szp);
109       if(t==pat)
110         ret.push_back(i);
111     }
112   return ret;
113 }
114
115 std::vector<int> PlayGround::BuildVectOfIdsFromVecBool(const std::vector<bool>& v)
116 {
117   std::size_t sz(std::count(v.begin(),v.end(),true)),i(0);
118   std::vector<int> ret(sz);
119   std::vector<bool>::const_iterator it(v.begin());
120   while(i<sz)
121     {
122       it=std::find(it,v.end(),true);
123       ret[i++]=std::distance(v.begin(),it);
124       it++;
125     }
126   return ret;
127 }
128
129 void PlayGround::highlightOnIds(const std::vector<int>& coreIds, std::vector<bool>& v) const
130 {
131   if(v.size()!=getNumberOfCoresAvailable())
132     throw Exception("PlayGround::highlightOnIds : oops ! invalid size !");
133   for(std::vector<int>::const_iterator it=coreIds.begin();it!=coreIds.end();it++)
134     v[*it]=true;
135 }
136
137 /*! 
138  * you must garantee coherence between PlayGround::deduceMachineFrom, PlayGround::getNumberOfWorkers, and PartDefinition::computeWorkerIdsCovered
139  */
140 // std::vector<bool> PlayGround::getFetchedCores(int nbCoresPerWorker) const
141 // {
142 //   int nbCores(getNumberOfCoresAvailable());
143 //   std::vector<bool> ret(nbCores,false);
144 //   if(nbCoresPerWorker==1)
145 //     std::fill(ret.begin(),ret.end(),true);
146 //   else
147 //     {
148 //       std::size_t posBg(0);
149 //       for(std::vector< std::pair<std::string,int> >::const_iterator it=_data.begin();it!=_data.end();it++)
150 //         {
151 //           int nbElemsToPutOn(((*it).second/nbCoresPerWorker)*nbCoresPerWorker);
152 //           std::fill(ret.begin()+posBg,ret.begin()+posBg+nbElemsToPutOn,true);
153 //           posBg+=(*it).second;
154 //         }
155 //     }
156 //   return ret;
157 //}
158 /*!
159  * follow getMaxNumberOfContainersCanBeHostedWithoutOverlap method
160  */
161 std::vector<std::size_t> PlayGround::getWorkerIdsFullyFetchedBy(int nbCoresPerComp, const std::vector<bool>& coreFlags) const
162 {
163   std::size_t posBg(0),posWorker(0);
164   std::vector<std::size_t> ret;
165   for(std::vector< std::pair<std::string,int> >::const_iterator it=_data.begin();it!=_data.end();it++)
166     {
167       int nbWorker((*it).second/nbCoresPerComp);
168       for(int j=0;j<nbWorker;j++,posWorker++)
169         {
170           std::vector<bool>::const_iterator it2(std::find(coreFlags.begin()+posBg+j*nbCoresPerComp,coreFlags.begin()+posBg+(j+1)*nbCoresPerComp,false));
171           if(it2==coreFlags.begin()+posBg+(j+1)*nbCoresPerComp)
172             ret.push_back(posWorker);
173         }
174       posBg+=(*it).second;
175     }
176   return ret;
177 }
178
179 std::vector< YACS::BASES::AutoRefCnt<PartDefinition> > PlayGround::partition(const std::vector< std::pair<const PartDefinition *, const ComplexWeight *> >& parts, const std::vector< int>& nbCoresPerShot) const
180 {
181   std::size_t sz(parts.size()),szs(getNumberOfCoresAvailable());
182   if (sz!=nbCoresPerShot.size())
183     throw Exception("PlayGround::partition : incoherent vector size !");
184   if(sz==0)
185     return std::vector< YACS::BASES::AutoRefCnt<PartDefinition> >();
186   if(sz==1)
187     {
188       const PartDefinition *pd(parts[0].first);
189       if(!pd)
190         throw Exception("Presence of null pointer as part def  0 !");
191       YACS::BASES::AutoRefCnt<PartDefinition> ret(pd->copy());
192       std::vector< YACS::BASES::AutoRefCnt<PartDefinition> > ret2(1,ret);
193       return ret2;
194     }
195   if(sz>31)
196     throw Exception("PlayGround::partition : not implemented yet for more than 31 ! You need to pay for it :)");
197   std::vector<bool> zeArr(szs*sz,false);
198   std::size_t i(0);
199   for(std::vector< std::pair<const PartDefinition *, const ComplexWeight *> >::const_iterator it=parts.begin();it!=parts.end();it++,i++)
200     {
201       const PartDefinition *pd((*it).first);
202       if(!pd)
203         throw Exception("Presence of null pointer as part def !");
204       if(pd->getPlayGround()!=this)
205         throw Exception("Presence of non homogeneous playground !");
206       std::vector<bool> bs(pd->getCoresOn()); // tab of length nbCores, with True or False for each Core
207       for(std::size_t j=0;j<szs;j++)
208         zeArr[j*sz+i]=bs[j]; // remplis une table avec les valeurs de bs. La table est [nb part] * [nb cores]
209     }
210   std::vector< std::vector<int> > retIds(sz);
211   for(std::size_t i=0;i<szs;i++)
212     {
213       std::vector<bool> code(zeArr.begin()+i*sz,zeArr.begin()+(i+1)*sz);// vecteur contenant le true/false d'un coeur pour ttes les partitions
214       std::vector<int> locIds(GetIdsMatching(zeArr,code)); // liste des coeurs qui peuvent correspondre au pattern code
215       std::vector<int> partsIds(BuildVectOfIdsFromVecBool(code));// pour chaque partition retourne l'id de la premiere partition à true
216       if(partsIds.empty())
217         continue;
218       std::vector<std::pair <const ComplexWeight *, int> > wg;
219       for(std::vector<int>::const_iterator it=partsIds.begin();it!=partsIds.end();it++)
220         {
221           wg.push_back(std::pair <const ComplexWeight *, int> (parts[*it].second, nbCoresPerShot[*it]));
222         }
223       std::vector< std::vector<int> > ress(splitIntoParts(locIds,wg));
224       std::size_t k(0);
225       for(std::vector<int>::const_iterator it=partsIds.begin();it!=partsIds.end();it++,k++)
226         {
227           retIds[*it].insert(retIds[*it].end(),ress[k].begin(),ress[k].end());
228         }
229     }
230   //
231   std::vector< YACS::BASES::AutoRefCnt<PartDefinition> > ret(sz);
232   for(std::size_t i=0;i<sz;i++)
233     {
234       std::set<int> s(retIds[i].begin(),retIds[i].end());
235       std::vector<int> v(s.begin(),s.end());
236       ret[i]=PartDefinition::BuildFrom(this,v);
237     }
238   return ret;
239 }
240
241 std::vector< std::vector<int> > PlayGround::splitIntoParts(const std::vector<int>& coreIds, const std::vector< std::pair <const ComplexWeight *, int> >& weights) const
242 {
243   std::size_t sz(weights.size());
244   if(sz==0)
245     return std::vector< std::vector<int> >();
246   std::vector< std::vector<int> > ret;
247   std::vector< std::vector<int> > disorderRet(sz);
248   std::vector<bool> zeArr(getNumberOfCoresAvailable(),false);
249   highlightOnIds(coreIds,zeArr);
250   int nbOfCoresToSplit(coreIds.size());
251   int totalSpace(coreIds.size());
252   int remainingSpace(totalSpace);
253   std::vector<int> nbOfCoresAllocated(sz);
254   std::vector<int> nbCoresPerShot(sz,-1);  
255   // first every other branchs take its minimal part of the cake
256   // and remove branch without valid weight
257   int i(0);
258   std::map<int,int> saveOrder;
259   const std::vector< std::pair <const ComplexWeight *, int> > sortedWeights(bigToTiny(weights, saveOrder));
260   for(std::vector<std::pair <const ComplexWeight *, int> >::const_iterator it=sortedWeights.begin();it!=sortedWeights.end();it++,i++)
261     {
262       nbCoresPerShot[i]=(*it).second;
263       if ((*it).first->isUnsetLoopWeight())
264         {
265           nbOfCoresAllocated[i]=nbCoresPerShot[i]; // branch with only elementary nodes
266         }
267       else if (!(*it).first->hasValidLoopWeight())
268         {
269           nbOfCoresAllocated[i]=(int)((double)totalSpace/(double)(sz)); // branch with undefined weight
270         }
271       else
272         {
273           nbOfCoresAllocated[i]=nbCoresPerShot[i];
274         }
275     }
276   remainingSpace-=std::accumulate(nbOfCoresAllocated.begin(), nbOfCoresAllocated.end(), 0);
277   //get critical path (between path with loopWeight)
278   int criticalPathRank=getCriticalPath(sortedWeights, nbOfCoresAllocated);
279   if (criticalPathRank!=-1)
280     {
281       // add cores to critical path while enough cores are availables
282           while (remainingSpace >= nbCoresPerShot[criticalPathRank])
283             {
284               nbOfCoresAllocated[criticalPathRank]+=nbCoresPerShot[criticalPathRank];
285               remainingSpace-=nbCoresPerShot[criticalPathRank];
286               criticalPathRank=getCriticalPath(sortedWeights, nbOfCoresAllocated);
287             }
288           //fill other paths with remaining cores (if possible) (reuse fromBigToTiny here?)
289           // and takePlace
290           int coresToAdd;
291           int j(0);
292           for(std::vector<int>::iterator it=nbOfCoresAllocated.begin();it!=nbOfCoresAllocated.end();it++,j++)
293             {
294               coresToAdd=((int)(remainingSpace/nbCoresPerShot[j]))*nbCoresPerShot[j];
295               *it+=coresToAdd;
296               remainingSpace-=coresToAdd;
297             }
298     }
299   int k(0);
300   for(std::vector<int>::iterator it=nbOfCoresAllocated.begin();it!=nbOfCoresAllocated.end();it++,k++)
301     {
302       disorderRet[k]=takePlace(*it,nbCoresPerShot[k],zeArr,k==(sz-1));
303     }   
304   ret=backToOriginalOrder(disorderRet, saveOrder);
305   return ret;
306 }
307
308 std::vector< std::pair <const ComplexWeight *, int> > PlayGround::bigToTiny(const std::vector< std::pair <const ComplexWeight *, int> > &weights, std::map<int,int> &saveOrder) const
309 {
310   int maxCoresPerShot(0), rankMax(0);
311   int i(0);
312   std::vector< std::pair <const ComplexWeight *, int> > ret;
313   std::size_t sz(weights.size());
314   while (ret.size()<sz)
315     {
316       for(std::vector<std::pair <const ComplexWeight *, int> >::const_iterator it=weights.begin();it!=weights.end();it++,i++)
317         {
318           if ((maxCoresPerShot<(*it).second) && (saveOrder.find(i)==saveOrder.end()))
319             {
320               maxCoresPerShot=(*it).second;
321               rankMax=i;
322             }
323         }
324       ret.push_back(std::pair <const ComplexWeight *, int>(weights[rankMax].first,weights[rankMax].second));
325       saveOrder[rankMax]=ret.size()-1;
326       maxCoresPerShot=0;
327       i=0;
328     }
329   return ret;   
330 }
331
332 std::vector< std::vector<int> > PlayGround::backToOriginalOrder(const std::vector< std::vector<int> > &disorderVec, const std::map<int,int> &saveOrder) const
333 {
334   std::vector< std::vector<int> > ret;
335   std::size_t sz(disorderVec.size());
336   if (disorderVec.size()!=saveOrder.size())
337     throw Exception("PlayGround::backToOriginalOrder : incoherent vector size !");
338   for (int i=0; i<sz; i++)
339       ret.push_back(disorderVec[saveOrder.at(i)]);
340   return ret;
341 }
342
343 int PlayGround::getCriticalPath(const std::vector<std::pair <const ComplexWeight *, int > >& weights, const std::vector<int>& nbOfCoresAllocated) const
344 {
345   double maxWeight(0.);
346   double pathWeight(0.);
347   int rankMaxPath(-1);
348   if ((weights.size()!=nbOfCoresAllocated.size()) || (weights.size()==0))
349     throw Exception("PlayGround::getCriticalPath : internal error !");
350   int i=0;
351   for(std::vector<std::pair <const ComplexWeight *, int> >::const_iterator it=weights.begin();it!=weights.end();it++,i++)
352     {
353       if (nbOfCoresAllocated[i]==0)
354         throw Exception("PlayGround::getCriticalPath : nbOfCoresAllocated is null! error !");
355       if (!(*it).first->isDefaultValue())
356         {
357               pathWeight=(*it).first->calculateTotalLength(nbOfCoresAllocated[i]);
358               if (pathWeight > maxWeight)
359                 {
360                   maxWeight=pathWeight;
361                   rankMaxPath=i;
362                 }
363         }         
364     }
365   return rankMaxPath;
366
367
368 std::vector<int> PlayGround::takePlace(int maxNbOfCoresToAlloc, int nbCoresPerShot, std::vector<bool>& distributionOfCores, bool lastOne) const
369 {
370   if(maxNbOfCoresToAlloc<1)
371     throw Exception("PlayGround::takePlace : internal error ! no space to alloc !");
372   int tmpMaxNbOfCoresToAlloc(maxNbOfCoresToAlloc);
373   if(lastOne)
374     tmpMaxNbOfCoresToAlloc=std::max(tmpMaxNbOfCoresToAlloc,(int)std::count(distributionOfCores.begin(),distributionOfCores.end(),true));
375   std::vector<int> ret;
376   std::vector<int> offsets(computeOffsets());
377   int nbFullItem(0);
378   std::size_t sz(offsets.size()-1);
379   for(std::size_t i=0;i<sz && tmpMaxNbOfCoresToAlloc>=nbCoresPerShot;i++)
380     {
381       int d(offsets[i+1]-offsets[i]);
382       if(nbCoresPerShot>d)
383         continue;
384       std::vector<bool> target(nbCoresPerShot,true);
385       for(int j=0;j<=d-nbCoresPerShot && tmpMaxNbOfCoresToAlloc>=nbCoresPerShot;)
386         {
387           std::vector<bool> t(distributionOfCores.begin()+offsets[i]+j,distributionOfCores.begin()+offsets[i]+j+nbCoresPerShot);
388           if(t==target)
389             {
390               nbFullItem++;
391               tmpMaxNbOfCoresToAlloc-=nbCoresPerShot;
392               std::fill(distributionOfCores.begin()+offsets[i]+j,distributionOfCores.begin()+offsets[i]+j+nbCoresPerShot,false);
393               for(int k=offsets[i]+j;k<offsets[i]+j+nbCoresPerShot;k++)
394                 ret.push_back(k);
395               j+=nbCoresPerShot;
396             }
397           else
398             j++;
399         }
400     }
401   if(nbFullItem>0)
402     return ret;
403   if(nbCoresPerShot<=1)
404     throw Exception("PlayGround::takePlace : internal error !");
405   // not enough contiguous place. Find the first wider contiguous place
406   for(int kk=std::min(nbCoresPerShot-1,tmpMaxNbOfCoresToAlloc);kk>=1;kk--)
407     {
408       for(std::size_t i=0;i<sz && tmpMaxNbOfCoresToAlloc>=kk;i++)
409         {
410           int d(offsets[i+1]-offsets[i]);
411           if(kk>d)
412             continue;
413           std::vector<bool> target(kk,true);
414           for(int j=0;j<=d-kk && tmpMaxNbOfCoresToAlloc>=kk;)
415             {
416               std::vector<bool> t(distributionOfCores.begin()+offsets[i]+j,distributionOfCores.begin()+offsets[i]+j+kk);
417               if(t==target)
418                 {
419                   nbFullItem++;
420                   tmpMaxNbOfCoresToAlloc-=kk;
421                   std::fill(distributionOfCores.begin()+offsets[i]+j,distributionOfCores.begin()+offsets[i]+j+kk,false);
422                   for(int k=offsets[i]+j;k<offsets[i]+j+kk;k++)
423                     ret.push_back(k);
424                   return ret;
425                 }
426               else
427                 j++;
428             }
429         }
430     }
431   throw Exception("PlayGround::takePlace : internal error ! All cores are occupied !");
432 }
433
434 int PlayGround::fromWorkerIdToResId(int workerId, int nbProcPerNode) const
435 {
436   std::size_t sz2(_data.size());
437   std::vector<int> deltas(sz2+1); deltas[0]=0;
438   for(std::size_t i=0;i<sz2;i++)
439     deltas[i+1]=deltas[i]+(_data[i].second)/nbProcPerNode;
440   int zePos(0);
441   while(zePos<sz2 && (workerId<deltas[zePos] || workerId>=deltas[zePos+1]))
442     zePos++;
443   if(zePos==sz2)
444     zePos=workerId%sz2;
445   return zePos;
446 }
447
448 /*! 
449  * you must garantee coherence between PlayGround::deduceMachineFrom, PlayGround::getNumberOfWorkers, and PartDefinition::computeWorkerIdsCovered
450  */
451 std::string PlayGround::deduceMachineFrom(int workerId, int nbProcPerNode) const
452 {
453   int zePos(fromWorkerIdToResId(workerId,nbProcPerNode));
454   return _data[zePos].first;
455 }
456
457 /*! 
458  * you must garantee coherence between PlayGround::deduceMachineFrom, PlayGround::getNumberOfWorkers, PlayGround::getFetchedCores and PartDefinition::computeWorkerIdsCovered
459  */
460 int PlayGround::getNumberOfWorkers(int nbCoresPerWorker) const
461 {
462   return getMaxNumberOfContainersCanBeHostedWithoutOverlap(nbCoresPerWorker);
463 }
464
465 PlayGround::~PlayGround()
466 {
467 }
468
469 //////////////////////
470
471 PartDefinition::PartDefinition(const PlayGround *pg)
472 {
473   _pg.takeRef(pg);
474 }
475
476 PartDefinition::PartDefinition(const PartDefinition& other):_pg(other._pg)
477 {
478 }
479
480 PartDefinition::~PartDefinition()
481 {
482 }
483
484 // std::vector< YACS::BASES::AutoRefCnt<PartDefinition> > PartDefinition::partition(const std::vector< const ComplexWeight *>& wgs) const
485 // {
486 //   std::size_t sz(wgs.size());
487 //   std::vector< std::pair<const PartDefinition *, const ComplexWeight *> > elts(sz);
488 //   for(std::size_t i=0;i<sz;i++)
489 //     elts[i]=std::pair<const PartDefinition *, const ComplexWeight *>(this,wgs[i]);
490 //   return getPlayGround()->partition(elts);
491 // }
492
493 YACS::BASES::AutoRefCnt<PartDefinition> PartDefinition::BuildFrom(const PlayGround *pg, const std::vector<int>& coreIds)
494 {
495   int spaceSz(pg->getNumberOfCoresAvailable()),sz(coreIds.size());
496   if(sz>spaceSz)
497     throw Exception("PartDefinition::BuildFrom : error 1 !");
498   if(sz==0)
499     throw Exception("PartDefinition::BuildFrom : error 2 !");
500   int zeStart(coreIds.front()),zeEnd(coreIds.back());
501   if(zeStart<0 || zeEnd<zeStart)
502     throw Exception("PartDefinition::BuildFrom : error ! The content of core Ids is not OK !");
503   for(std::size_t i=0;i<sz-1;i++)
504     if(coreIds[i+1]<coreIds[i])
505       throw Exception("PartDefinition::BuildFrom : error ! The content of core Ids is not OK 2 !");
506   if(zeEnd-zeStart+1!=sz)
507     {
508       YACS::BASES::AutoRefCnt<PartDefinition> pd(new NonContigPartDefinition(pg,coreIds));
509       return pd;
510     }
511   if(sz==spaceSz)
512     {
513       YACS::BASES::AutoRefCnt<PartDefinition> pd(new AllPartDefinition(pg));
514       return pd;
515     }
516   YACS::BASES::AutoRefCnt<PartDefinition> pd(new ContigPartDefinition(pg,zeStart,zeEnd+1));
517   return pd;
518 }
519
520 void PartDefinition::stashPart(int nbCoresStashed, double weightOfRemain, YACS::BASES::AutoRefCnt<PartDefinition>& pdStashed, YACS::BASES::AutoRefCnt<PartDefinition>& pdRemain) const
521 {
522   if(nbCoresStashed<=0)
523     throw Exception("stashPart : Invalid nbCoresStashed value !");
524   if(weightOfRemain<=0.)
525     throw Exception("stashPart : Invalid weight !");
526   std::vector<bool> coresOn(getCoresOn());
527   int nbCoresAvailable(std::count(coresOn.begin(),coresOn.end(),true));
528   std::vector<int> ids(PlayGround::BuildVectOfIdsFromVecBool(coresOn));
529   if(nbCoresAvailable==0)
530     throw Exception("PartDefinition::stashPart : no available cores !");
531   if(nbCoresAvailable<=nbCoresStashed)
532     {
533       int n0((int)(1./(1.+weightOfRemain)*nbCoresAvailable)); n0=std::max(n0,1);
534       int n1(nbCoresAvailable-n0);
535       if(n1<=0)
536         {
537           pdStashed=PartDefinition::BuildFrom(getPlayGround(),ids);
538           pdRemain=PartDefinition::BuildFrom(getPlayGround(),ids);
539         }
540       else
541         {
542           std::vector<int> ids0(ids.begin(),ids.begin()+n0),ids1(ids.begin()+n0,ids.end());
543           pdStashed=PartDefinition::BuildFrom(getPlayGround(),ids0);
544           pdRemain=PartDefinition::BuildFrom(getPlayGround(),ids1);
545         }
546     }
547   else
548     {
549       std::vector<int> ids0(ids.begin(),ids.begin()+nbCoresStashed),ids1(ids.begin()+nbCoresStashed,ids.end());
550       pdStashed=PartDefinition::BuildFrom(getPlayGround(),ids0);
551       pdRemain=PartDefinition::BuildFrom(getPlayGround(),ids1);
552     }
553 }
554
555 /*! 
556  * you must garantee coherence between PlayGround::deduceMachineFrom, PlayGround::getNumberOfWorkers, and PartDefinition::computeWorkerIdsCovered
557  */
558 std::vector<std::size_t> PartDefinition::computeWorkerIdsCovered(int nbCoresPerComp) const
559 {
560   std::vector<bool> coresOn(getCoresOn());
561   return _pg->getWorkerIdsFullyFetchedBy(nbCoresPerComp,coresOn);
562 }
563
564 //////////////////////
565
566 ContigPartDefinition::ContigPartDefinition(const PlayGround *pg, int zeStart, int zeStop):PartDefinition(pg),_start(zeStart),_stop(zeStop)
567 {
568   if(_start<0 || _stop<_start || _stop>getSpaceSize())
569     throw Exception("ContigPartDefinition constructor : Invalid input values");
570 }
571
572 ContigPartDefinition::ContigPartDefinition(const ContigPartDefinition& other):PartDefinition(other),_start(other._start),_stop(other._stop)
573 {
574 }
575
576 std::string ContigPartDefinition::printSelf() const
577 {
578   std::ostringstream oss;
579   oss << "Contiguous : start=" << _start << " stop=" << _stop;
580   return oss.str();
581 }
582
583 std::vector<bool> ContigPartDefinition::getCoresOn() const
584 {
585   std::vector<bool> ret(getSpaceSize(),false);
586   for(int i=_start;i<_stop;i++)
587     ret[i]=true;
588   return ret;
589 }
590
591 ContigPartDefinition *ContigPartDefinition::copy() const
592 {
593   return new ContigPartDefinition(*this);
594 }
595
596 int ContigPartDefinition::getNumberOfCoresConsumed() const
597 {
598   return _stop-_start;
599 }
600
601 //////////////////////
602
603 NonContigPartDefinition::NonContigPartDefinition(const PlayGround *pg, const std::vector<int>& ids):PartDefinition(pg),_ids(ids)
604 {
605   checkOKIds();
606 }
607
608 NonContigPartDefinition::NonContigPartDefinition(const ContigPartDefinition& other):PartDefinition(other)
609 {
610 }
611
612 std::string NonContigPartDefinition::printSelf() const
613 {
614   std::ostringstream oss;
615   oss << "Non contiguous : ";
616   for(std::vector<int>::const_iterator it=_ids.begin();it!=_ids.end();it++)
617     oss << *it << ", ";
618   return oss.str();
619 }
620
621 std::vector<bool> NonContigPartDefinition::getCoresOn() const
622 {
623   std::vector<bool> ret(getSpaceSize(),false);
624   for(std::vector<int>::const_iterator it=_ids.begin();it!=_ids.end();it++)
625     ret[*it]=true;
626   return ret;
627 }
628
629 NonContigPartDefinition *NonContigPartDefinition::copy() const
630 {
631   return new NonContigPartDefinition(*this);
632 }
633
634 int NonContigPartDefinition::getNumberOfCoresConsumed() const
635 {
636   return _ids.size();
637 }
638
639 void NonContigPartDefinition::checkOKIds() const
640 {
641   int maxVal(getSpaceSize());
642   if(_ids.empty())
643     return;
644   int val(_ids.front());
645   if(val<0 || val>=maxVal)
646     throw Exception("checkOKIds : error 2 !");
647   std::size_t sz(_ids.size());
648   for(std::size_t i=0;i<sz-1;i++)
649     {
650       if(_ids[i+1]<=_ids[i])
651         throw Exception("checkOKIds : error 1 !");
652       if(_ids[i+1]>=maxVal)
653         throw Exception("checkOKIds : error 3 !");
654     }
655 }
656
657 //////////////////////
658
659 AllPartDefinition::AllPartDefinition(const AllPartDefinition& other):PartDefinition(other)
660 {
661 }
662
663 std::string AllPartDefinition::printSelf() const
664 {
665   std::ostringstream oss;
666   oss << "All";
667   return oss.str();
668 }
669
670 std::vector<bool> AllPartDefinition::getCoresOn() const
671 {
672   std::vector<bool> ret(getSpaceSize(),true);
673   return ret;
674 }
675
676 AllPartDefinition *AllPartDefinition::copy() const
677 {
678   return new AllPartDefinition(*this);
679 }
680
681 int AllPartDefinition::getNumberOfCoresConsumed() const
682 {
683   return getSpaceSize();
684 }
685
686 //////////////////////
687  
688  std::vector<int> ForTestOmlyHPContCls::getIDS() const
689  {
690    std::size_t sz(_ids.size());
691    std::vector<int> ret(sz);
692    for(std::size_t i=0;i<sz;i++)
693      ret[i]=_ids[i];
694    return ret;
695  }