politopix  4.1.0
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
DoubleDescription_Rn.h
Go to the documentation of this file.
1 // politopix allows to make computations on polytopes such as finding vertices, intersecting, Minkowski sums, ...
2 // Copyright (C) 2012-2016 : Delos Vincent
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Lesser General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Lesser General Public License for more details.
13 //
14 // You should have received a copy of the GNU Lesser General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
16 //
19 // I2M (UMR CNRS 5295 / University of Bordeaux)
20 
21 #ifndef DOUBLEDESCRIPTION_Rn
22 #define DOUBLEDESCRIPTION_Rn
23 
24 #include <math.h>
25 #include <numeric>
26 #include <set>
27 #include <map>
28 #include "Tracking.h"
29 #include "Neighbours_Rn.h"
30 
31 
32 
49 template< class POLYHEDRON, class ITERATOR, class REDUNDANCY_PROCESSING > class DoubleDescription {
50 
51  public:
52  DoubleDescription(POLYHEDRON poly, ITERATOR ite, REDUNDANCY_PROCESSING redproc, int truncationStep):_redundancyProcessing(redproc) {
53  std::vector< boost::shared_ptr<Generator_Rn_SD> > listOfGenSD;
54  // Generator_Rn => Generator_Rn_SD
55  // From the current generators make a list of generators dedicated to work in the data structure algorithm.
56  // Make sure the list of half-space numbers is sorted as we want to use algorithms further.
57  poly->getListOfGeneratorsSD(listOfGenSD);
58  _redundancyProcessing.initNumberOfVerticesPerHalfSpace(listOfGenSD, truncationStep); // Deal with redundancy.
59  //_redundancyProcessing.dumpListOfRedundantHS( std::cout );
60 
61  // Do the hard job now.
62  _isEmpty = !compute(poly, ite, truncationStep, listOfGenSD);
63 
64  if (_isEmpty == false) {
65  // Set the pointers from the generators to the half-spaces before dealing with redundancy - as the redundancy
66  // processing algorithm will change the numbers of the half-spaces. Here recycle the old pointers stored in
67  // the polyhedron to build the new list with the created generators.
68  poly->setListOfGeneratorsSD(listOfGenSD);
69  // Include all the generators now.
70  _redundancyProcessing.unhookRedundantHalfSpaces(poly);
71  //poly->dump(std::cout);
72  }
73  }
74 
78  POLYHEDRON poly,
79  ITERATOR ite,
80  REDUNDANCY_PROCESSING redproc,
81  int truncationStep,
82  TrackingOperatorToResult& trackerVdesc,
83  TrackingOperatorToResult& trackerHdesc):_redundancyProcessing(redproc) {
84  std::vector< boost::shared_ptr<Generator_Rn_SD> > listOfGenSD;
85  // Generator_Rn => Generator_Rn_SD
86  // From the current generators make a list of generators dedicated to work in the data structure algorithm.
87  // Make sure the list of half-space numbers is sorted as we want to use algorithms further.
88  poly->getListOfGeneratorsSD(listOfGenSD);
89  _redundancyProcessing.initNumberOfVerticesPerHalfSpace(listOfGenSD, truncationStep); // Deal with redundancy.
90  //_redundancyProcessing.dumpListOfRedundantHS( std::cout );
91 
92  // Do the hard job now.
93  _isEmpty = !compute(poly, ite, truncationStep, listOfGenSD);
94 
95  if (_isEmpty == false) {
96  // Store the modifications in the binary operation tracker.
97  // Operator1_Entity[i] = (Generator_Rn_SD::Status, Result_Entity[j])
98  // Operator2_Entity[k] = (Generator_Rn_SD::Status, Result_Entity[l])
99  // Result_Entity[m] = (Generator_Rn_SD::Status, (Operator1_Entity[p], Operator2_Entity[q]))
100  unsigned int nbRes=0;
101  std::vector< boost::shared_ptr<Generator_Rn_SD> >::const_iterator iteGenSD;
102  {for (iteGenSD=listOfGenSD.begin(); iteGenSD!=listOfGenSD.end(); ++iteGenSD) {
103  // In the tracker, the operand entities have been set to Operator_DELETED by default and the
104  // result entities have been set by default to Result_UNCHANGED.
105  Generator_Rn_SD::Status thisStatus = (*iteGenSD)->getStatus();
106  unsigned int nbOp1 = (*iteGenSD)->getGeneratorNumber();
107  if (thisStatus == Generator_Rn_SD::CREATED || thisStatus == Generator_Rn_SD::CREATED_AND_MODIFIED) {
108  trackerVdesc.setResultEntityAsCreated(nbRes);
109  trackerVdesc.setResult_Operator(nbRes,-1);
110  }
111  else if (thisStatus == Generator_Rn_SD::MODIFIED) {
112  trackerVdesc.setResultEntityAsModified(nbRes);
113  trackerVdesc.setResult_Operator(nbRes,nbOp1);
114  trackerVdesc.setOperatorEntityAsModified(nbOp1);
115  trackerVdesc.setOperator_Result(nbOp1,nbRes);
116  }
117  else if (thisStatus == Generator_Rn_SD::UNCHANGED) {
118  trackerVdesc.setResultEntityAsUnchanged(nbRes);
119  trackerVdesc.setResult_Operator(nbRes,nbOp1);
120  trackerVdesc.setOperatorEntityAsUnchanged(nbOp1);
121  trackerVdesc.setOperator_Result(nbOp1,nbRes);
122  }
123  ++nbRes;
124  }}
125  // Set the pointers from the generators to the half-spaces before dealing with redundancy - as the
126  // redundancy processing algorithm will change the numbers of the half-spaces.
127  poly->setListOfGeneratorsSD(listOfGenSD);
128  // Process the half-spaces now.
129  _redundancyProcessing.markHdescription(trackerHdesc, truncationStep);
130  _redundancyProcessing.unhookRedundantHalfSpaces(poly);
131  //poly->dump(std::cout);
132  }
133  }
134 
135  bool getIsEmpty() const {return _isEmpty;}
136 
139  std::vector< boost::shared_ptr<Generator_Rn_SD> >& GN_list,
140  const boost::shared_ptr<HalfSpace_Rn>& currentHalfSpace,
141  std::vector<double>& GN_IN_sp,
142  std::vector<double>& GN_OUT_sp,
143  std::vector< boost::shared_ptr<Generator_Rn_SD> >& GN_IN,
144  std::vector< boost::shared_ptr<Generator_Rn_SD> >& GN_OUT,
145  std::vector< boost::shared_ptr<Generator_Rn_SD> >& GN_ON)
146  {
147  int GeneratorNumber=0;
148  double TOL = Rn::getTolerance();
149  double halfSpaceNorm =
150  std::inner_product(currentHalfSpace->begin(), currentHalfSpace->end(), currentHalfSpace->begin(), 0.);
151  halfSpaceNorm = sqrt(halfSpaceNorm);
152  std::vector< boost::shared_ptr<Generator_Rn_SD> >::iterator iteGN;
153  for (iteGN=GN_list.begin(); iteGN!=GN_list.end(); ++iteGN) {
154  //const boost::shared_ptr<Generator_Rn_SD>& currentGenerator = iteGN.current();
155  double scalarProduct =
156  std::inner_product((*iteGN)->begin(), (*iteGN)->end(), currentHalfSpace->begin(), 0.);
157  //boost::numeric::ublas::inner_prod(currentGenerator->vect(), currentHalfSpace->vect());
158 #ifdef DEBUG
159  unsigned int RnDIM=currentHalfSpace->dimension();
160  std::cout.precision(15);
161  std::cout << "# V" << GeneratorNumber << " = [";
162  {for (unsigned int ii=0; ii<RnDIM; ii++) {
163  std::cout << (*iteGN)->getCoordinate(ii);
164  if (ii != RnDIM-1)
165  std::cout << ", ";
166  }}
167  std::cout << "]" << std::endl << "{ ";
168  {for (unsigned int ii=0; ii<(*iteGN)->numberOfFacets(); ii++) {
169  std::cout << (*iteGN)->getFacet(ii) << " ";
170  }}
171  std::cout << "}" << std::endl;
172  std::cout << "dotP = " << scalarProduct;
173  std::cout << ", dist = " << (scalarProduct+currentHalfSpace->getConstant()) / halfSpaceNorm;
174 #endif
175  //std::cout << "sp = " << scalarProduct << " ";
176  double distanceToHyperplane = (scalarProduct+currentHalfSpace->getConstant()) / halfSpaceNorm;
177  if (distanceToHyperplane > TOL) {
178  GN_IN.push_back((*iteGN));
179  GN_IN_sp.push_back(scalarProduct);
180  }
181  else if (distanceToHyperplane < -TOL) {
182  GN_OUT.push_back((*iteGN));
183  GN_OUT_sp.push_back(scalarProduct);
184  }
185  else {
186  GN_ON.push_back((*iteGN));
187  }
188 #ifdef DEBUG
190  if (distanceToHyperplane > TOL)
191  currentState = HalfSpace_Rn::hs_IN;
192  else if (distanceToHyperplane < -TOL)
193  currentState = HalfSpace_Rn::hs_OUT;
194  else
195  currentState = HalfSpace_Rn::hs_ON;
196  std::cout << ", state = " << HalfSpace_Rn::getStateAsText(currentState) << std::endl;
197 #endif
198  GeneratorNumber++;
199  }
200  }
201 
203  bool compute(POLYHEDRON poly, ITERATOR iteHS, int truncationStep, std::vector< boost::shared_ptr<Generator_Rn_SD> >& listOfGenSD) {
204  // Store the scalar product result.
205  std::vector<double> GN_IN_sp;
206  std::vector<double> GN_OUT_sp;
207  // Store generators IN, ON, OUT or newly created.
208  std::vector< boost::shared_ptr<Generator_Rn_SD> > GN_IN;
209  std::vector< boost::shared_ptr<Generator_Rn_SD> > GN_OUT;
210  std::vector< boost::shared_ptr<Generator_Rn_SD> > GN_ON;
211  std::vector< boost::shared_ptr<Generator_Rn_SD> > GN_new;
212  // Remove redundant half spaces.
213  std::vector< boost::shared_ptr<HalfSpace_Rn> > redundantHS;
214  int halfspaceNumber=truncationStep, generatorNumber=0;
215  unsigned int RnDIM=poly->dimension();
216  double TOL2=Rn::getTolerance()*Rn::getTolerance();
217 
218 #ifdef DEBUG
219  std::cout << std::endl << "DoubleDescription::compute(" << truncationStep << ")" << std::endl;
220 #endif
221  // We use this algorithm to compute vertices for a single polyhedron or to intersect two polyhedra.
222  // In the last case we truncate the polyhedron A generators net by the the polyhedron B half-spaces
223  // so we need to step forward in the half-space list where B constraints begin.
224  //constIteratorOfListOfGeometricObjects< boost::shared_ptr<HalfSpace_Rn> > iteHS(poly->getListOfHalfSpaces());
225  generatorNumber = poly->numberOfGenerators();
226  iteHS.setStep(truncationStep);
227  {for (iteHS.begin(); iteHS.end()!=true; iteHS.next()) {
228  const boost::shared_ptr<HalfSpace_Rn>& currentHalfSpace = iteHS.current();
229  _redundancyProcessing.addHalfSpace();
230 #ifdef DEBUG
231  double halfSpaceNorm = std::inner_product(currentHalfSpace->begin(), currentHalfSpace->end(), currentHalfSpace->begin(), 0.);
232  halfSpaceNorm = sqrt(halfSpaceNorm);
233  std::cout << "Facet number " << halfspaceNumber << std::endl;
234  std::cout << "H" << halfspaceNumber << " = ";
235  currentHalfSpace->dump(std::cout);
236  std::cout << ", norm=" << halfSpaceNorm;
237  std::cout << std::endl;
238 #endif
239 
240  // Fill the arrays of generators according to their position with respect to the current half-space.
241  computeVertexStates(listOfGenSD, currentHalfSpace, GN_IN_sp, GN_OUT_sp, GN_IN, GN_OUT, GN_ON);
242 
243  // Check whether the current constraint excludes all Generators.
244  if (GN_IN.empty() == true) {
245  // NO INTERSECTION
246 #ifdef DEBUG
247  std::cout << "Truncation is empty." << std::endl;
248 #endif
249  poly->reset();
250  return false;
251  }
252 
253  // Check whether the current constraint is redundant. Only available for polytopes.
254  // For polyhedral cones, replace Rn::getDimension() by (Rn::getDimension()-1).
255  if (GN_OUT.empty() == true) {// && VX_ON.size() < numberOfGeneratorsPerFacet()) {
256  // REDUNDANT HALFSPACE (be careful when modifying a list under iterator)
257  redundantHS.push_back(currentHalfSpace);
258  //_listOfHalfSpaces.removeCurrentHalfSpace(iteHS.currentIteratorNumber());
259  //_listOfHalfSpaces.erase(HSPos);
260 #ifdef DEBUG
261  std::cout << "VX_OUT= " << GN_OUT.size() << std::endl;
262  std::cout << "VX_IN = " << GN_IN.size() << std::endl;
263  std::cout << "VX_ON = " << GN_ON.size() << std::endl;
264  std::cout << "redundantHS = " << redundantHS.size() << std::endl;
265  std::cout << "============================================" << std::endl;
266 #endif
267  }
268  else if (GN_IN.empty() != true) {
269  // Build the list of all possible new generators.
270  Neighbours_Rn newGeneratorsTool;
271  {
272  // OUT-IN & OUT-ON
273  unsigned int count_OUT=0;
274  std::vector< boost::shared_ptr<Generator_Rn_SD> >::const_iterator iteGN_OUT;
275  {for (iteGN_OUT=GN_OUT.begin(); iteGN_OUT!=GN_OUT.end(); ++iteGN_OUT, ++count_OUT) {
276  unsigned int count_IN=0;
277  std::vector< boost::shared_ptr<Generator_Rn_SD> >::const_iterator iteGN_IN;
278  {for (iteGN_IN=GN_IN.begin(); iteGN_IN!=GN_IN.end(); ++iteGN_IN, ++count_IN) {
279  std::vector< unsigned int > commonPFacets;
280  if (_redundancyProcessing.checkNeighbours(poly, *iteGN_IN, *iteGN_OUT, commonPFacets) == true)
281  newGeneratorsTool.addGenerator(
282  commonPFacets,
283  count_IN,
284  count_OUT,
286  }}
287  unsigned int count_ON=0;
288  std::vector< boost::shared_ptr<Generator_Rn_SD> >::const_iterator iteGN_ON;
289  {for (iteGN_ON=GN_ON.begin(); iteGN_ON!=GN_ON.end(); ++iteGN_ON, ++count_ON) {
290  std::vector< unsigned int > commonPFacets;
291  if (_redundancyProcessing.checkNeighbours(poly, *iteGN_ON, *iteGN_OUT, commonPFacets) == true)
292  newGeneratorsTool.addGenerator(
293  commonPFacets,
294  count_ON,
295  count_OUT,
297  }}
298  }}
299  // ON-IN & ON-ON
300  unsigned int count_ON1=0;
301  std::vector< boost::shared_ptr<Generator_Rn_SD> >::const_iterator iteGN_ON1;
302  {for (iteGN_ON1=GN_ON.begin(); iteGN_ON1!=GN_ON.end(); ++iteGN_ON1, ++count_ON1) {
303  unsigned int count_IN=0;
304  std::vector< boost::shared_ptr<Generator_Rn_SD> >::const_iterator iteGN_IN;
305  {for (iteGN_IN=GN_IN.begin(); iteGN_IN!=GN_IN.end(); ++iteGN_IN, ++count_IN) {
306  std::vector< unsigned int > commonPFacets;
307  if (_redundancyProcessing.checkNeighbours(poly, *iteGN_IN, *iteGN_ON1, commonPFacets) == true)
308  newGeneratorsTool.addGenerator(
309  commonPFacets,
310  count_IN,
311  count_ON1,
313  }}
314  unsigned int count_ON2=0;
315  std::vector< boost::shared_ptr<Generator_Rn_SD> >::const_iterator iteGN_ON2;
316  {for (iteGN_ON2=GN_ON.begin(); iteGN_ON2!=GN_ON.end(); ++iteGN_ON2, ++count_ON2) {
317  std::vector< unsigned int > commonPFacets;
318  if (iteGN_ON1 != iteGN_ON2 &&
319  _redundancyProcessing.checkNeighbours(poly, *iteGN_ON1, *iteGN_ON2, commonPFacets) == true)
320  newGeneratorsTool.addGenerator(
321  commonPFacets,
322  count_ON1,
323  count_ON2,
325  }}
326  }}
327  }
328  //newGeneratorsTool.dump(std::cout);
329  for (newGeneratorsTool.begin(); newGeneratorsTool.end()!=true; newGeneratorsTool.next()) {
330 #ifdef DEBUG
331  std::cout << "NGB1= " << newGeneratorsTool.currentGenInNumber() << ", NGB2= " << newGeneratorsTool.currentGenOutNumber() << std::endl;
332 #endif
333  // Create a new Generator as a combination of currentGeneratorIn and currentGeneratorOut.
334  double ay = GN_OUT_sp[newGeneratorsTool.currentGenOutNumber()];
335  double az = GN_IN_sp[newGeneratorsTool.currentGenInNumber()];
336  // currentGeneratorIn and currentGeneratorOut are genuine neighbours.
337  const boost::shared_ptr<Generator_Rn_SD>& currentGeneratorIn = GN_IN[newGeneratorsTool.currentGenInNumber()];
338  const boost::shared_ptr<Generator_Rn_SD>& currentGeneratorOut = GN_OUT[newGeneratorsTool.currentGenOutNumber()];
339  // Mark the new as CREATED.
340  boost::shared_ptr<Generator_Rn_SD> newV(new Generator_Rn_SD(RnDIM, generatorNumber, Generator_Rn_SD::CREATED));
341  ++generatorNumber;
342  poly->createTruncatedGenerator(currentGeneratorOut, currentGeneratorIn, newV, ay, az, currentHalfSpace->getConstant());
343  // Fill in the list of facets for the new Generator.
344  std::vector< unsigned int > commonFacets;
345  // Get facets.
346  _redundancyProcessing.checkNeighbours(poly, currentGeneratorIn, currentGeneratorOut, commonFacets);
347  newV->setAllFacets(commonFacets);
348  // Do not add the current half-space at this step but wait a little bit more.
349 
350  // The new Generator is ready to be inserted in the data structure if not equal to
351  // another one with state ON.
352  bool notEq=true;
353  std::set< unsigned int > setOfFacets;
354  std::vector< boost::shared_ptr<Generator_Rn_SD> >::const_iterator iteGN_ON_eq;
355  {for (iteGN_ON_eq=GN_ON.begin(); iteGN_ON_eq!=GN_ON.end() && notEq==true; ++iteGN_ON_eq) {
356  if ((*iteGN_ON_eq)->isEqual2(newV, RnDIM, TOL2)) {
357  notEq = false;
358  // newV has no future so just transfer its facets to the current equal generator.
359  // Make sure not to include twice currentHalfSpace.
360  newV->exportFacets(setOfFacets);
361  (*iteGN_ON_eq)->exportFacets(setOfFacets);
362  (*iteGN_ON_eq)->importFacets(setOfFacets);
363  (*iteGN_ON_eq)->orderFacets();
364  }
365  }}
366  std::vector< boost::shared_ptr<Generator_Rn_SD> >::const_iterator iteGN_NEW_eq;
367  {for (iteGN_NEW_eq=GN_new.begin(); iteGN_NEW_eq!=GN_new.end() && notEq==true; ++iteGN_NEW_eq) {
368  if ((*iteGN_NEW_eq)->isEqual2(newV, RnDIM, TOL2)) {
369  notEq = false;
370  // newV has no future so just transfer its facets to the current equal generator.
371  newV->setFacet(halfspaceNumber);
372  newV->exportFacets(setOfFacets);
373  (*iteGN_NEW_eq)->exportFacets(setOfFacets);
374  (*iteGN_NEW_eq)->importFacets(setOfFacets);
375  (*iteGN_NEW_eq)->orderFacets();
376  }
377  }}
378  if (notEq == true) {
379  newV->setFacet(halfspaceNumber);
380  GN_new.push_back(newV);
381 #ifdef DEBUG
382  std::cout << "New Generator = [";
383  newV->save(std::cout);
384  std::cout << "] GeneratorIN [";
385  currentGeneratorIn->save(std::cout);
386  std::cout << "], VX_IN_sp=" << az << " GeneratorOUT [";
387  currentGeneratorOut->save(std::cout);
388  std::cout << "], VX_OUT_sp=" << ay << std::endl;
389 #endif
390  }
391  else {
392 #ifdef DEBUG
393  std::cout << "No new Generator as [";
394  newV->save(std::cout);
395  std::cout << "] is equal to a previous one." << std::endl;
396 #endif
397  }
398  } // for (newGeneratorsTool.begin(); newGeneratorsTool.end()!=true; newGeneratorsTool.next()) {
399 
400 #ifdef DEBUG
401  std::cout << "VX_OUT= " << GN_OUT.size() << std::endl;
402  std::cout << "VX_IN = " << GN_IN.size() << std::endl;
403  std::cout << "VX_ON = " << GN_ON.size() << std::endl;
404  std::cout << "redundantHS = " << redundantHS.size() << std::endl;
405  std::cout << "============================================" << std::endl;
406 #endif
407 
408  // All the generators with state ON must have a new facet.
409  std::vector< boost::shared_ptr<Generator_Rn_SD> >::const_iterator iteGN_ON;
410  for (iteGN_ON=GN_ON.begin(); iteGN_ON!=GN_ON.end(); ++iteGN_ON) {
411  (*iteGN_ON)->setFacet(halfspaceNumber);
412  if ((*iteGN_ON)->getStatus() == Generator_Rn_SD::CREATED)
413  (*iteGN_ON)->setStatus(Generator_Rn_SD::CREATED_AND_MODIFIED);
414  else if ((*iteGN_ON)->getStatus() == Generator_Rn_SD::UNCHANGED)
415  (*iteGN_ON)->setStatus(Generator_Rn_SD::MODIFIED);
416  // Insert the ON generators in the IN list as this list will be the official one soon.
417  GN_IN.push_back(*iteGN_ON);
418  }
419  // The current face must mark all the vertices with state ON.
420  // No need to do more than marking as all vertices ON are now embedded in GN_IN.
421  _redundancyProcessing.updateNumberOfVerticesPerHalfSpace(halfspaceNumber, GN_ON); // Deal with redundancy.
422 
423  std::vector< boost::shared_ptr<Generator_Rn_SD> >::const_iterator iteGN_new;
424  for (iteGN_new=GN_new.begin(); iteGN_new!=GN_new.end(); ++iteGN_new) {
425  // Insert the new generators in the IN list as this list will be the official one soon.
426  GN_IN.push_back(*iteGN_new);
427  _redundancyProcessing.incrementNumberForVerticesForHalfSpace(*iteGN_new); // Deal with redundancy.
428  }
429  // For the redundancy processing :
430  // . all the vertices with state NEW must have their face counter incremented++
431  // . all the vertices with state ON must have their face counter incremented++ (in a global way)
432  // . all the vertices with state OUT must have their face counter decremented--
433 
434  std::vector< boost::shared_ptr<Generator_Rn_SD> >::const_iterator iteGN_OUT;
435  for (iteGN_OUT=GN_OUT.begin(); iteGN_OUT!=GN_OUT.end(); ++iteGN_OUT) {
436  _redundancyProcessing.decrementNumberForVerticesForHalfSpace(*iteGN_OUT); // Deal with redundancy.
437  }
438 
439  _redundancyProcessing.updateListOfRedundantHalfSpaces(poly->numberOfGeneratorsPerFacet()); // Deal with redundancy.
440 
441  // Remove all the generators OUT and replace them with the set IN-ON-new.
442  listOfGenSD = GN_IN;
443  } // else if (GN_IN.empty() != true) {
444 
445  GN_OUT_sp.clear();
446  GN_OUT.clear();
447  GN_IN_sp.clear();
448  GN_IN.clear();
449  GN_ON.clear();
450  GN_new.clear();
451  halfspaceNumber++;
452  //_redundancyProcessing.dumpSD(std::cout);
453  }} // for (iteHS.begin(); iteHS.end()!=true; iteHS.next()) {
454 
455  return true;
456  }
457 
458  protected:
460  bool _isEmpty;
462  REDUNDANCY_PROCESSING _redundancyProcessing;
463 
464 };
465 
467 template< class POLYHEDRON > class NoRedundancyProcessing {
468  public:
470 
472 
474  virtual bool checkNeighbours(
475  POLYHEDRON poly,
476  const boost::shared_ptr<Generator_Rn>& genIn,
477  const boost::shared_ptr<Generator_Rn>& genOut,
478  std::vector< boost::shared_ptr<HalfSpace_Rn> >& commonFacets) {
479  return poly->checkNeighbours(genIn, genOut, commonFacets);
480  }
481 
483  virtual bool checkNeighbours(
484  POLYHEDRON poly,
485  const boost::shared_ptr<Generator_Rn>& genIn,
486  const boost::shared_ptr<Generator_Rn>& genOut,
487  std::vector< HalfSpace_Rn* >& commonFacets) {
488  return poly->checkNeighbours(genIn, genOut, commonFacets);
489  }
490 
492  void initNumberOfVerticesPerHalfSpace(const std::vector< boost::shared_ptr<Generator_Rn> >&) {}
493 
495  void updateNumberOfVerticesPerHalfSpace(const boost::shared_ptr<HalfSpace_Rn>& , unsigned int) {}
496 
498  void incrementNumberForVerticesForHalfSpace(const boost::shared_ptr<Generator_Rn>&) {}
499 
501  void decrementNumberForVerticesForHalfSpace(const boost::shared_ptr<Generator_Rn>&) {}
502 
504  void updateListOfRedundantHalfSpaces(unsigned int) {}
505 
506  void unhookRedundantHalfSpaces(POLYHEDRON) {}
507 
508 };
509 
510 
514 template< class POLYHEDRON > class StrongRedundancyProcessing {
515 
516  public:
518  _neigbourhoodCondition = ngbCond;
519  }
520 
522 
524  const POLYHEDRON,
525  std::vector< unsigned int >& getNumberOfVerticesPerHalfSpace) {
526  getNumberOfVerticesPerHalfSpace = _numberOfVerticesPerHalfSpace;
527  }
528 
530  const POLYHEDRON,
531  std::vector< unsigned int >&,
532  std::set< unsigned int >& getListOfRedundantHS) {
533  getListOfRedundantHS = _listOfRedundantHS;
534  }
535 
537  void initNumberOfVerticesPerHalfSpace(const std::vector< boost::shared_ptr<Generator_Rn_SD> >& LG, unsigned int nbHS) {
538  _allGenPerHS.clear();
539  _listOfRedundantHS.clear();
541  _numberOfHalfSpaces = nbHS;
542 
543  // First init to 0 to be able to increment
544  {for (unsigned int j=0; j<nbHS; ++j) {
545  _numberOfVerticesPerHalfSpace.push_back(0);
546  }}
547  std::vector< boost::shared_ptr<Generator_Rn_SD> >::const_iterator constITER_GN;
548  for (constITER_GN=LG.begin(); constITER_GN!=LG.end(); ++constITER_GN) {
549  {for (unsigned int j=0; j<(*constITER_GN)->numberOfFacets(); j++) {
550  unsigned int nbF = (*constITER_GN)->getFacet(j);
552  }}
553  }
554  //std::map< boost::shared_ptr<HalfSpace_Rn>, unsigned int >::const_iterator
555  //mit(numberOfVertexPerHalfSpace.begin()), mend(numberOfVertexPerHalfSpace.end());
556  //for (; mit!=mend; ++mit)
557  //std::cout << mit->first << '\t' << mit->second << std::endl;
558 
559  // Now deal with the set of vertices itself contained by the faces
560  // to see if a given set can be included into another one. But first of
561  // all set the list of back pointers.
562  {for (unsigned int j=0; j<nbHS; ++j) {
563  std::set< unsigned int > genSet;
564  _allGenPerHS.push_back(genSet);
565  }}
566  for (constITER_GN=LG.begin(); constITER_GN!=LG.end(); ++constITER_GN) {
567  {for (unsigned int j=0; j<(*constITER_GN)->numberOfFacets(); j++) {
568  unsigned int F = (*constITER_GN)->getFacet(j);
569  // GenPerFacet: number(HalfSpace_Rn) => {Generator_Rn_SD_0*, Generator_Rn_SD_1*, Generator_Rn_SD_2*, ...}
570  // Fill the data structure storing all the generators for a given facet.
571  _allGenPerHS[F].insert( (*constITER_GN)->getGeneratorNumber() );
572  }}
573  }
574  //dumpSD(std::cout);
575  }
576 
578  void addHalfSpace() {
579  _numberOfVerticesPerHalfSpace.push_back(0);
580  std::set< unsigned int > genSet;
581  _allGenPerHS.push_back(genSet);
583  }
584 
587  unsigned int HS,
588  const std::vector< boost::shared_ptr<Generator_Rn_SD> >& GN_ON) {
589  _numberOfVerticesPerHalfSpace[ HS ] += GN_ON.size();
590  std::vector< boost::shared_ptr<Generator_Rn_SD> >::const_iterator iteGN_ON;
591  for (iteGN_ON=GN_ON.begin(); iteGN_ON!=GN_ON.end(); ++iteGN_ON)
592  _allGenPerHS[ HS ].insert( (*iteGN_ON)->getGeneratorNumber() );
593  }
594 
596  void incrementNumberForVerticesForHalfSpace(const boost::shared_ptr<Generator_Rn_SD>& GEN) {
597  for (unsigned int l=0; l<GEN->numberOfFacets(); ++l) {
598  _numberOfVerticesPerHalfSpace[ GEN->getFacet(l) ]++;
599  _allGenPerHS[ GEN->getFacet(l) ].insert( GEN->getGeneratorNumber() );
600  }
601  }
602 
604  void decrementNumberForVerticesForHalfSpace(const boost::shared_ptr<Generator_Rn_SD>& GEN) {
605  for (unsigned int l=0; l<GEN->numberOfFacets(); ++l) {
606  _numberOfVerticesPerHalfSpace[ GEN->getFacet(l) ]--;
607  _allGenPerHS[ GEN->getFacet(l) ].erase( GEN->getGeneratorNumber() );
608  }
609  }
610 
614  POLYHEDRON poly,
615  const boost::shared_ptr<Generator_Rn_SD>& genIn,
616  const boost::shared_ptr<Generator_Rn_SD>& genOut,
617  std::vector< unsigned int >& commonFacets) {
618  // Compute the intersection on sorted lists of facets.
619  std::set_intersection(genIn->facetsBegin(), genIn->facetsEnd(), genOut->facetsBegin(), genOut->facetsEnd(),
620  std::inserter(commonFacets, commonFacets.end()));
621  // For polyhedral cones neigbourhoodCondition() is Rn::getDimension()-1, for polytopes it is Rn::getDimension()-2.
622  if (commonFacets.size() >= _neigbourhoodCondition)
623  return true;
624 
625  return false;
626  }
627 
630  virtual void updateListOfRedundantHalfSpaces(unsigned int numberOfGeneratorsPerFacet) {
631  {for(unsigned int i=0; i<_numberOfVerticesPerHalfSpace.size(); ++i) {
632  // Stop when we reach the current half-space being processed, it was the last inserted.
633  if (_numberOfVerticesPerHalfSpace[i] < numberOfGeneratorsPerFacet) {
634  if (_listOfRedundantHS.insert( i ).second == true) {
635 #ifdef DEBUG
636  std::cout << "Redundant " << i;
637  std::cout << std::endl;
638 #endif
639  }
640  }
641  }}
642 
643  // Now we've checked that half-spaces have the correct minimum number of generators we need to
644  // perform a more complicated task. Now run the map to see if a set of generators can be
645  // included into another one. In this case it means that the current half-space is redundant.
646  unsigned int i1,i2;
647  std::vector< std::set< unsigned int > >::const_iterator it_1, it_2;
648  {for (it_1=_allGenPerHS.begin(), i1=0; it_1!=_allGenPerHS.end(); ++it_1, ++i1) {
649  {for (it_2=_allGenPerHS.begin(), i2=0; it_2!=_allGenPerHS.end(); ++it_2, ++i2) {
650  if (it_1!=it_2 && _listOfRedundantHS.find(i1)==_listOfRedundantHS.end() && _listOfRedundantHS.find(i2)==_listOfRedundantHS.end()) {
651  if (it_1->size() > it_2->size()) {
652  if (std::includes(it_1->begin(), it_1->end(), it_2->begin(), it_2->end())) {
653  _listOfRedundantHS.insert(i2);
654 #ifdef DEBUG
655  std::cout << "New redundant facet: " << i2 << std::endl;
656 #endif
657  }
658  }
659  else if (it_1->size() < it_2->size()) {
660  if (std::includes(it_2->begin(), it_2->end(), it_1->begin(), it_1->end())) {
661  _listOfRedundantHS.insert(i1);
662 #ifdef DEBUG
663  std::cout << "New redundant facet: " << i1 << std::endl;
664 #endif
665  }
666  }
667  else {
668  // Unnecessary check for equality
669  }
670  }
671  }}
672  }}
673  }
674 
675  void fillListOfRedundantHS(const POLYHEDRON poly) { updateListOfRedundantHalfSpaces(poly->numberOfGeneratorsPerFacet()); }
676 
677  void unhookRedundantHalfSpaces(POLYHEDRON poly) {
678  //fillListOfRedundantHS( poly );
679  // Unhook redundant half-spaces from the vertices.
680  unsigned int hsNb;
681  if (!_listOfRedundantHS.empty()) {
683  {for (iteHS.begin(), hsNb=0; iteHS.end()!=true; iteHS.next(), ++hsNb) {
684  if (_listOfRedundantHS.find(hsNb) != _listOfRedundantHS.end()) {
685  // We have a genuine redundant half-space.
687  {for (iteGN.begin(); iteGN.end()!=true; iteGN.next()) {
688  boost::shared_ptr<Generator_Rn> gen = iteGN.current();
689  {for (int j=gen->numberOfFacets()-1; j>=0; j--) {
690  if (iteHS.current() == gen->getFacet(j))
691  gen->removeFacet(j);
692  }}
693  }}
694  }
695  }}
696  }
697  // Add to the list of redundant half-spaces the ones which are not
698  // referenced at all by vertices from the beginning of the process.
700  {for (iteHS2.begin(), hsNb=0; iteHS2.end()!=true; iteHS2.next(), ++hsNb) {
701  if (_listOfRedundantHS.find(hsNb) == _listOfRedundantHS.end()) {
702  if (_numberOfVerticesPerHalfSpace[hsNb] == 0) {
703  // The half-space has not been found so it's not in use at all and is redundant.
704  _listOfRedundantHS.insert(hsNb);
705  }
706  }
707  }}
708  if (!_listOfRedundantHS.empty()) {
709 #ifdef DEBUG
710  std::cout << "Remove " << _listOfRedundantHS.size() << " redundant facets: ";
711 #endif
712  std::vector< unsigned int > HS2Remove;
713  std::set< unsigned int >::const_iterator it;
714  {for (it=_listOfRedundantHS.begin(); it!=_listOfRedundantHS.end(); ++it) {
715 #ifdef DEBUG
716  std::cout << *it << " ";
717 #endif
718  HS2Remove.push_back(*it);
719  }}
720  std::sort(HS2Remove.begin(), HS2Remove.end(), std::greater<unsigned int>());
721  std::vector< unsigned int >::const_iterator it2;
722  {for (it2=HS2Remove.begin(); it2!=HS2Remove.end(); ++it2) {
723  // Do not forget to begin by the bigger to remove as we could change the ordering.
724  poly->removeHalfSpace(*it2);
725  }}
726 #ifdef DEBUG
727  std::cout << std::endl;
728 #endif
729  }
730  }
731 
732  // Mark as UNCHANGED, CREATED or DELETED the half-spaces going through the double description process.
733  void markHdescription(TrackingOperatorToResult& trackerHdesc, unsigned int truncationStep) {
735  // Before truncation step they are UNCHANGED by default, then they are CREATED by default.
736  for (unsigned int i=0; i<truncationStep; ++i)
737  trackerHdesc.setOperatorEntityAsUnchanged(i);
738  for (unsigned int i=truncationStep; i<_numberOfHalfSpaces; ++i)
739  trackerHdesc.setResultEntityAsCreated(i);
740  std::set< unsigned int >::const_iterator iteRED=_listOfRedundantHS.begin();
741  for ( ; iteRED!=_listOfRedundantHS.end(); ++iteRED)
742  trackerHdesc.setOperatorEntityAsDeleted(*iteRED);
743  }
744 
745  void dumpListOfRedundantHS(POLYHEDRON poly, std::ostream &this_stream) {
746  unsigned int RnDIM=poly->dimension();
747  this_stream << "List of redundant half-spaces :" << std::endl;
748  unsigned int hsNb;
749  if (!_listOfRedundantHS.empty()) {
751  {for (iteHS.begin(), hsNb=0; iteHS.end()!=true; iteHS.next(), ++hsNb) {
752  if (_listOfRedundantHS.find(hsNb) != _listOfRedundantHS.end()) {
753  boost::shared_ptr<HalfSpace_Rn> currentHalfSpace = iteHS.current();
754  this_stream << "H = (" << currentHalfSpace->getConstant() << ", ";
755  {for (unsigned int ii=0; ii<RnDIM; ii++) {
756  this_stream << currentHalfSpace->getCoefficient(ii);
757  if (ii != RnDIM-1)
758  this_stream << ", ";
759  }}
760  this_stream << ")" << std::endl;
761  }
762  }}
763  }
764  }
765 
766  void dumpSD(std::ostream &this_stream) {
767  std::vector< std::set< unsigned int > >::const_iterator iteGHS;
768  this_stream << "*** number(HalfSpace_Rn0) => {Generator_Rn0*, Generator_Rn1*, Generator_Rn2*, ...}" << std::endl;
769  unsigned int counter=0;
770  {for (iteGHS=_allGenPerHS.begin(); iteGHS!=_allGenPerHS.end(); ++iteGHS) {
771  this_stream << counter << " => { ";
772  std::copy(iteGHS->begin(), iteGHS->end(), std::ostream_iterator<unsigned int>(std::cout, " ") );
773  this_stream << "}" << std::endl;
774  ++counter;
775  }}
776  this_stream << "*** number of generators per half-spaces : ";
777  std::copy(_numberOfVerticesPerHalfSpace.begin(), _numberOfVerticesPerHalfSpace.end(), std::ostream_iterator<unsigned int>(std::cout, " ") );
778  this_stream << std::endl;
779  this_stream << "*** list of redundant half-spaces : ";
780  std::copy(_listOfRedundantHS.begin(), _listOfRedundantHS.end(), std::ostream_iterator<unsigned int>(std::cout, " ") );
781  this_stream << std::endl;
782  }
783 
784  protected:
785  // Deal with the number of generators per half-space.
787  // number(HalfSpace_Rn0) => {Generator_Rn0*, Generator_Rn1*, Generator_Rn2*, ...}
788  std::vector< std::set< unsigned int > > _allGenPerHS;
790  std::vector< unsigned int > _numberOfVerticesPerHalfSpace;
792  std::set< unsigned int > _listOfRedundantHS;
794  unsigned int _numberOfHalfSpaces;
797 };
798 
799 #endif
void unhookRedundantHalfSpaces(POLYHEDRON poly)
bool compute(POLYHEDRON poly, ITERATOR iteHS, int truncationStep, std::vector< boost::shared_ptr< Generator_Rn_SD > > &listOfGenSD)
The main function splitting the polyhedron cone or polytope 1-skeleton with a list of half-spaces...
bool checkNeighbours(POLYHEDRON poly, const boost::shared_ptr< Generator_Rn_SD > &genIn, const boost::shared_ptr< Generator_Rn_SD > &genOut, std::vector< unsigned int > &commonFacets)
void next()
Iterator function.
void setResult_Operator(unsigned int nbRes, int nb)
Set the link between the nb-th entity of operator1 and the nbRes-th entity of the result...
Definition: Tracking.h:89
void begin()
Iterator function.
void updateListOfRedundantHalfSpaces(unsigned int)
Only useful in the case of dealing and processing redundancy.
DoubleDescription(POLYHEDRON poly, ITERATOR ite, REDUNDANCY_PROCESSING redproc, int truncationStep)
void addHalfSpace()
Make space for a new half-space.
void initNumberOfVerticesPerHalfSpace(const std::vector< boost::shared_ptr< Generator_Rn_SD > > &LG, unsigned int nbHS)
Make sure all back pointers from half-spaces to vertices are set.
bool end()
Iterator function.
void incrementNumberForVerticesForHalfSpace(const boost::shared_ptr< Generator_Rn > &)
Only useful in the case of dealing and processing redundancy.
Class dedicated to degeneration processing when looking for neighbours. Let A be a polytope of wher...
Definition: Neighbours_Rn.h:59
void updateNumberOfVerticesPerHalfSpace(unsigned int HS, const std::vector< boost::shared_ptr< Generator_Rn_SD > > &GN_ON)
The current face must mark all the vertices with state ON.
unsigned int currentGenOutNumber()
Iterator function.
void computeVertexStates(std::vector< boost::shared_ptr< Generator_Rn_SD > > &GN_list, const boost::shared_ptr< HalfSpace_Rn > &currentHalfSpace, std::vector< double > &GN_IN_sp, std::vector< double > &GN_OUT_sp, std::vector< boost::shared_ptr< Generator_Rn_SD > > &GN_IN, std::vector< boost::shared_ptr< Generator_Rn_SD > > &GN_OUT, std::vector< boost::shared_ptr< Generator_Rn_SD > > &GN_ON)
For each generator compute its state according to the current half-space.
void setResultEntityAsUnchanged(unsigned int nb)
Mark as Result_UNCHANGED the nb-th entity before the operation.
Definition: Tracking.h:67
void initNumberOfVerticesPerHalfSpace(const std::vector< boost::shared_ptr< Generator_Rn > > &)
Only useful in the case of dealing and processing redundancy.
void updateNumberOfVerticesPerHalfSpace(const boost::shared_ptr< HalfSpace_Rn > &, unsigned int)
Only useful in the case of dealing and processing redundancy.
void fillListOfRedundantHS(const POLYHEDRON poly)
virtual bool checkNeighbours(POLYHEDRON poly, const boost::shared_ptr< Generator_Rn > &genIn, const boost::shared_ptr< Generator_Rn > &genOut, std::vector< HalfSpace_Rn * > &commonFacets)
Check whether two generators are neighbors in the context of not taking into account redundancy...
unsigned int _neigbourhoodCondition
To define the relation between generators.
const GEOMETRIC_OBJECT current()
Return the current geometric element.
void dumpListOfRedundantHS(POLYHEDRON poly, std::ostream &this_stream)
virtual void updateListOfRedundantHalfSpaces(unsigned int numberOfGeneratorsPerFacet)
std::vector< std::set< unsigned int > > _allGenPerHS
Store all raw back pointers to know which vertices belong to a given half-space.
virtual bool checkNeighbours(POLYHEDRON poly, const boost::shared_ptr< Generator_Rn > &genIn, const boost::shared_ptr< Generator_Rn > &genOut, std::vector< boost::shared_ptr< HalfSpace_Rn > > &commonFacets)
Check whether two generators are neighbors in the context of not taking into account redundancy...
Makes the assumption we do not need to process redundant half-spaces in a specific way...
void markHdescription(TrackingOperatorToResult &trackerHdesc, unsigned int truncationStep)
std::vector< unsigned int > _numberOfVerticesPerHalfSpace
To know about how many vertices refer to a given half-space.
unsigned int _numberOfHalfSpaces
The total number of processed half-spaces.
void unhookRedundantHalfSpaces(POLYHEDRON)
bool _isEmpty
Store the current state of the intersection.
void setNumbersOfEntities(unsigned int nbEntBefore, unsigned int nbEntAfter)
Definition: Tracking.h:47
static polito_EXPORT double getTolerance()
Give the minimum distance between two points.
Definition: Rn.cpp:31
This class stores static function that dispatch the main geometric values we use. ...
Definition: Tracking.h:41
void setOperatorEntityAsUnchanged(unsigned int nb)
Mark as Operator_UNCHANGED the nb-th entity before the operation.
Definition: Tracking.h:58
This class can be more time-consuming than WeakRedundancyProcessing or NoRedundancyProcessing because...
unsigned int currentGenInNumber()
Iterator function.
void decrementNumberForVerticesForHalfSpace(const boost::shared_ptr< Generator_Rn > &)
Only useful in the case of dealing and processing redundancy.
This class is designed to run the list of all geometric objects representing a polytope.
void fillListOfRedundantHS(const POLYHEDRON, std::vector< unsigned int > &, std::set< unsigned int > &getListOfRedundantHS)
DoubleDescription(POLYHEDRON poly, ITERATOR ite, REDUNDANCY_PROCESSING redproc, int truncationStep, TrackingOperatorToResult &trackerVdesc, TrackingOperatorToResult &trackerHdesc)
void setResultEntityAsModified(unsigned int nb)
Mark as Result_MODIFIED the nb-th entity after the operation.
Definition: Tracking.h:70
A n-coordinates generator for internal data structure. It can be a vertex or an edge whether it is em...
Definition: Generator_Rn.h:225
static std::string getStateAsText(const HalfSpace_Rn::State &)
void decrementNumberForVerticesForHalfSpace(const boost::shared_ptr< Generator_Rn_SD > &GEN)
Make sure all the half-spaces belonging to a given generator have their vertices number decremented...
StrongRedundancyProcessing(unsigned int ngbCond)
void addGenerator(const std::vector< unsigned int > &commonFacets, unsigned int numbergenIN, unsigned int numbergenOUT, HalfSpace_Rn::State state)
Tell whether a pseudo neighbor is a genuine one comparing set of half-spaces.
Definition: Neighbours_Rn.h:69
void fillNumberOfVerticesPerHalfSpace(const POLYHEDRON, std::vector< unsigned int > &getNumberOfVerticesPerHalfSpace)
void setOperator_Result(unsigned int nb, int nbRes)
Set the link between the nb-th entity of operator1 and the nbRes-th entity of the result...
Definition: Tracking.h:86
void setResultEntityAsCreated(unsigned int nb)
Mark as Result_CREATED the nb-th entity after the operation.
Definition: Tracking.h:76
std::set< unsigned int > _listOfRedundantHS
To know whether an half-space has been ticked redundant or not.
The algorithm implemented here is an incremental algorithm as mentioned in How Good are Convex Hull ...
void setOperatorEntityAsModified(unsigned int nb)
Mark as Operator_MODIFIED the nb-th entity before the operation.
Definition: Tracking.h:61
void incrementNumberForVerticesForHalfSpace(const boost::shared_ptr< Generator_Rn_SD > &GEN)
Make sure all the half-spaces belonging to a given generator have their vertices number incremented...
void dumpSD(std::ostream &this_stream)
void setOperatorEntityAsDeleted(unsigned int nb)
Mark as Operator_DELETED the nb-th entity before the operation.
Definition: Tracking.h:64
REDUNDANCY_PROCESSING _redundancyProcessing
This class is dedicated to dealing with redundant half-spaces with the desired policy.