politopix  5.0.0
PolyhedralAlgorithms_Rn.cpp
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) 2015-2020 : Delos Vincent
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU 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 General Public License for more details.
13 //
14 // You should have received a copy of the GNU 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 #include <iostream>
22 #include <sstream>
23 #include <vector>
24 #include <math.h>
25 #include <numeric>
26 #include <boost/numeric/ublas/io.hpp>
27 #include <boost/numeric/ublas/lu.hpp>
28 #include <boost/numeric/ublas/vector.hpp>
29 #include <boost/numeric/ublas/matrix.hpp>
30 #include <boost/numeric/ublas/symmetric.hpp>
31 #include <boost/numeric/ublas/operation.hpp>
32 #include <boost/numeric/ublas/matrix_proxy.hpp>
33 #include <boost/timer.hpp>
34 #include "Rn.h"
35 #include "Polytope_Rn.h"
36 #include "IO_Polytope.h"
37 #include "NormalFan_Rn.h"
39 
40 //typedef std::vector< unsigned int > ListOfFaces;
41 
42 
43 void FaceEnumeration::Compute(const boost::shared_ptr<Polytope_Rn>& thisPolytope) {
44  FaceEnumeration FE(thisPolytope);
45  FaceEnumeration::ComputeWithFacets(thisPolytope, FE);
46  FaceEnumeration::ComputeWithVertices(thisPolytope, FE);
47 }
48 
49 void FaceEnumeration::Compute(const boost::shared_ptr<Polytope_Rn>& thisPolytope, FaceEnumeration& FaceEnum) {
50  FaceEnumeration::ComputeWithFacets(thisPolytope, FaceEnum);
51  FaceEnumeration::ComputeWithVertices(thisPolytope, FaceEnum);
52 }
53 
54 void FaceEnumeration::ComputeWithFacets(const boost::shared_ptr<Polytope_Rn>& thisPolytope, FaceEnumeration& FaceEnum) {
55  unsigned int RnDIM = Rn::getDimension();
56  FaceEnum._allFacesWithFacets.clear();
57  std::set< ListOfFaces > allPotentialFaces;
58  std::vector< ListOfFaces > thisListOfFacetsPerVertices;
59  constIteratorOfListOfGeometricObjects< boost::shared_ptr<Generator_Rn> > constITER_GN1(thisPolytope->getListOfGenerators());
60  {for (constITER_GN1.begin(); constITER_GN1.end()!=true; constITER_GN1.next()) {
61  unsigned int NbFacets = constITER_GN1.current()->numberOfFacets();
62  ListOfFaces thisListOfFaces;
63  {for (unsigned int j=0; j<NbFacets; j++) {
64  unsigned int NbFj = thisPolytope->getHalfSpaceNumber( constITER_GN1.current()->getFacet(j) );
65  // GenPerFacet: number(HalfSpace_Rn) => {Generator_Rn_0, Generator_Rn_1, Generator_Rn_2, ...}
66  thisListOfFaces.push_back( NbFj );
67  }}
68  thisListOfFacetsPerVertices.push_back( thisListOfFaces );
69  allPotentialFaces.insert(thisListOfFaces);
70  }}
71  FaceEnum._allFacesWithFacets.push_back( thisListOfFacetsPerVertices );
72  //std::cout << "RnDIM = " << RnDIM << std::endl;
73  {for (unsigned int dimensionOfFace=1; dimensionOfFace<=RnDIM; ++dimensionOfFace) {
74  //std::cout << std::endl << "D=" << dimensionOfFace << std::endl;
75  std::vector< ListOfFaces > kp1_Faces;
76  std::set< ListOfFaces > kp1_FacesSet;
77  std::vector< ListOfFaces >& k_Faces = FaceEnum._allFacesWithFacets[dimensionOfFace-1];
78  std::vector< ListOfFaces >::iterator it1 = k_Faces.begin(), it2 = k_Faces.begin();
79  for (it1 = k_Faces.begin(); it1 != k_Faces.end(); ) {
80  // To know whether we had to move forward.
81  bool it1StepForward = false;
82  for (it2 = it1+1; it2 != k_Faces.end(); ) {
83  std::vector< unsigned int > interFace;
84  std::set_intersection(it1->begin(), it1->end(), it2->begin(), it2->end(), std::inserter(interFace, interFace.end()));
85  // Check whether this face as already been processed.
86  //std::cout << std::endl << "| it1 = { ";
87  //std::copy(it1->begin(), it1->end(), std::ostream_iterator<unsigned int>(std::cout, " ") );
88  //std::cout << "} INTER it2 = { ";
89  //std::copy(it2->begin(), it2->end(), std::ostream_iterator<unsigned int>(std::cout, " ") );
90  //std::cout << "} = { ";
91  //std::copy(interFace.begin(), interFace.end(), std::ostream_iterator<unsigned int>(std::cout, " ") );
92  //std::cout << "} ";
93  //std::cout << "inserted ";
94  if (interFace.empty() == false) {
95  if (interFace == *it2) {
96  it2 = k_Faces.erase(it2);
97  //std::cout << "(it2 erased) ";
98  }
99  else
100  ++it2;
101  if (interFace == *it1) {
102  it1 = k_Faces.erase(it1);
103  //std::cout << "(it1 erased) ";
104  it1StepForward = true;
105  if (it1 != k_Faces.end())
106  it2 = it1+1;
107  }
108  //std::cout << "in kp1 ";
109  // Check it was not already in.
110  if (kp1_FacesSet.insert(interFace).second == true)
111  kp1_Faces.push_back(interFace);
112  }
113  else {
114  //std::cout << "empty intersection ";
115  ++it2;
116  }
117  } // for (it2 = k_Faces.begin(); it2 != k_Faces.end(); ) {
118  // Only move forward iif we didn't do it before.
119  if (it1StepForward == false)
120  ++it1;
121  }
122  FaceEnum._allFacesWithFacets.push_back(kp1_Faces);
123  }}
124  //FaceEnum.printFacesWithFacets(std::cout);
125 }
126 
127 void FaceEnumeration::ComputeWithVertices(const boost::shared_ptr<Polytope_Rn>& thisPolytope, FaceEnumeration& FaceEnum) {
128  unsigned int nbHS = thisPolytope->numberOfHalfSpaces();
129  FaceEnum._allFacesWithVertices.clear();
130  FaceEnum._allFacesWithVertices.resize(Rn::getDimension()+1);
131  // number(HalfSpace_Rn0) => {Generator_Rn0*, Generator_Rn1*, Generator_Rn2*, ...}
132  std::vector< std::vector< unsigned int > > allGenPerHS;
133  {for (unsigned int j=0; j<nbHS; ++j) {
134  std::vector< unsigned int > genSet;
135  allGenPerHS.push_back(genSet);
136  }}
137 
138  unsigned int generatorNumber=0;
139  constIteratorOfListOfGeometricObjects< boost::shared_ptr<Generator_Rn> > iteGN(thisPolytope->getListOfGenerators());
140  {for (iteGN.begin(); iteGN.end()!=true; iteGN.next()) {
141  {for (unsigned int ii=0; ii<iteGN.current()->numberOfFacets(); ii++) {
142  unsigned int fctNumber = thisPolytope->getHalfSpaceNumber( iteGN.current()->getFacet(ii) );
143  allGenPerHS[fctNumber].push_back( iteGN.currentIteratorNumber() );
144  }}
145  ++generatorNumber;
146  }}
147 
148  unsigned int dim = 0;
149  std::vector< std::vector< ListOfFaces > >::const_iterator iteF;
150  for (iteF=FaceEnum._allFacesWithFacets.begin(); iteF!=FaceEnum._allFacesWithFacets.end(); ++iteF) {
151  //this_ostream << "F" << dim << ": ";
152  std::vector< ListOfFaces >::const_iterator iteFF;
153  for (iteFF=iteF->begin(); iteFF!=iteF->end(); ++iteFF) {
154  ListOfFaces::const_iterator iteFFF;
155  //this_ostream << " { ";
156  iteFFF=iteFF->begin();
157  std::vector< unsigned int > INTER = allGenPerHS[*iteFFF];
158  ++iteFFF;
159  for (; iteFFF!=iteFF->end(); ++iteFFF) {
160  //this_ostream << *iteFFF << " ";
161  std::vector< unsigned int > partial_INTER;
162  std::set_intersection(INTER.begin(), INTER.end(),
163  allGenPerHS[*iteFFF].begin(), allGenPerHS[*iteFFF].end(),
164  std::inserter(partial_INTER, partial_INTER.end()));
165  INTER = partial_INTER;
166  }
167  FaceEnum._allFacesWithVertices[dim].push_back(INTER);
168  //std::copy(INTER.begin(), INTER.end(), std::ostream_iterator<unsigned int>(std::cout, " ") );
169  //this_ostream << "} ";
170  }
171  //this_ostream << std::endl;
172  ++dim;
173  }
174 }
175 
176 void FaceEnumeration::printFacesWithFacets(std::ostream &this_ostream) const {
177  unsigned int dim = 0, allSizes = 0;
178  std::vector< std::vector< ListOfFaces > >::const_iterator iteF;
179  for (iteF=_allFacesWithFacets.begin(); iteF!=_allFacesWithFacets.end(); ++iteF) {
180  allSizes = allSizes + iteF->size();
181  }
182  // Add the empty polytope and the total polytope.
183  allSizes = allSizes + 2;
184  this_ostream << "FaceEnumeration::printFacesWithFacets, total number of elements = " << allSizes << std::endl;
185  for (iteF=_allFacesWithFacets.begin(); iteF!=_allFacesWithFacets.end(); ++iteF) {
186  this_ostream << "F" << dim << ": ";
187  std::vector< ListOfFaces >::const_iterator iteFF;
188  for (iteFF=iteF->begin(); iteFF!=iteF->end(); ++iteFF) {
189  ListOfFaces::const_iterator iteFFF;
190  this_ostream << " { ";
191  for (iteFFF=iteFF->begin(); iteFFF!=iteFF->end(); ++iteFFF) {
192  this_ostream << *iteFFF << " ";
193  }
194  this_ostream << "} ";
195  }
196  this_ostream << std::endl;
197  ++dim;
198  }
199 }
200 
201 void FaceEnumeration::printFacesWithVertices(std::ostream &this_ostream) const {
202  unsigned int dim = 0, allSizes = 0;
203  std::vector< std::vector< ListOfFaces > >::const_iterator iteF;
204  for (iteF=_allFacesWithVertices.begin(); iteF!=_allFacesWithVertices.end(); ++iteF) {
205  allSizes = allSizes + iteF->size();
206  }
207  // Add the empty polytope and the total polytope.
208  allSizes = allSizes + 2;
209  this_ostream << "FaceEnumeration::printFacesWithVertices, total number of elements = " << allSizes << std::endl;
210  for (iteF=_allFacesWithVertices.begin(); iteF!=_allFacesWithVertices.end(); ++iteF) {
211  this_ostream << "F" << dim << ": ";
212  std::vector< ListOfFaces >::const_iterator iteFF;
213  for (iteFF=iteF->begin(); iteFF!=iteF->end(); ++iteFF) {
214  ListOfFaces::const_iterator iteFFF;
215  this_ostream << " { ";
216  for (iteFFF=iteFF->begin(); iteFFF!=iteFF->end(); ++iteFFF) {
217  this_ostream << *iteFFF << " ";
218  }
219  this_ostream << "} ";
220  }
221  this_ostream << std::endl;
222  ++dim;
223  }
224 }
225 
226 void FaceEnumeration::printFacesWithVerticesToSage(std::ostream &this_ostream) const {
227  unsigned int dim = 0, allSizes = 0;
228  std::vector< std::vector< ListOfFaces > >::const_iterator iteF;
229  for (iteF=_allFacesWithVertices.begin(); iteF!=_allFacesWithVertices.end(); ++iteF) {
230  allSizes = allSizes + iteF->size();
231  }
232  // Add the empty polytope and the total polytope.
233  allSizes = allSizes + 2;
234  this_ostream << "FaceEnumeration::printFacesWithVerticesToSage, total number of elements = " << allSizes << std::endl;
235  for (iteF=_allFacesWithVertices.begin(); iteF!=_allFacesWithVertices.end(); ++iteF) {
236  this_ostream << "F" << dim << ": " << std::endl;
237  std::vector< ListOfFaces >::const_iterator iteFF;
238  std::vector< ListOfFaces >::const_iterator stopFF=iteF->end()-1;
239  for (iteFF=iteF->begin(); iteFF!=stopFF && iteFF!=iteF->end(); ++iteFF) {
240  ListOfFaces::const_iterator iteFFF, stopFFF=iteFF->end()-1;
241  this_ostream << "(";
242  for (iteFFF=iteFF->begin(); iteFFF!=stopFFF; ++iteFFF) {
243  this_ostream << *iteFFF << ", ";
244  }
245  this_ostream << *iteFFF << "), ";
246  }
247  // Print the last one.
248  if (iteFF!=iteF->end()) {
249  ListOfFaces::const_iterator iteFFF, stopFFF=iteFF->end()-1;
250  this_ostream << "(";
251  for (iteFFF=iteFF->begin(); iteFFF!=stopFFF; ++iteFFF) {
252  this_ostream << *iteFFF << ", ";
253  }
254  this_ostream << *iteFFF << ") ";
255  }
256  this_ostream << std::endl;
257  ++dim;
258  }
259 }
260 
261 void FaceEnumeration::load(const std::string& filename, std::vector< std::vector< ListOfFaces > >& latt) {
262  std::ifstream file(filename.c_str(), std::ifstream::in);
263  if (!file) {
264  std::string s("Unable to open ");
265  s += filename;
266  s += "\n";
267  throw std::ios_base::failure(s);
268  }
269  FaceEnumeration::load(file, latt);
270  file.close();
271 }
272 
273 void FaceEnumeration::save(const std::string& filename, const std::vector< std::vector< ListOfFaces > >& latt) {
274  std::ofstream file(filename.c_str());
275  if (!file) {
276  std::string s("Unable to open ");
277  s += filename;
278  s += "\n";
279  throw std::ios_base::failure(s);
280  }
281  FaceEnumeration::save(file, latt);
282  file.close();
283 }
284 
285 void FaceEnumeration::load(std::istream& this_stream, std::vector< std::vector< ListOfFaces > >& latt) {
286  std::string line;
287  // Read the comment line.
288  std::getline(this_stream, line);
289  // Get the 2 integers : space dimension, number of faces.
290  std::getline(this_stream, line);
291  std::istringstream iline(line);
292  unsigned int spaceDimension, totalNumberOfFaces;
293  iline >> spaceDimension;
294  iline >> totalNumberOfFaces;
295  latt.resize(spaceDimension+1);
296  unsigned nbReadFaces = 0;
297  while (nbReadFaces != totalNumberOfFaces) {
298  ListOfFaces thisOne;
299  std::getline(this_stream, line);
300  std::istringstream iline3(line);
301  unsigned int dimensionOfFace, numberOfVtx, val;
302  iline3 >> dimensionOfFace;
303  iline3 >> numberOfVtx;
304  if (dimensionOfFace > spaceDimension) {
305  std::string errorMsg("FaceEnumeration::load() wrong face dimension");
306  throw std::out_of_range(errorMsg);
307  }
308  // dimensionOfFace numberOfVtx a0 a1 ... an
309  for (unsigned int count=0; count<numberOfVtx; ++count) {
310  iline3 >> val;
311  thisOne.push_back(val);
312  }
313  latt[dimensionOfFace].push_back(thisOne);
314  ++nbReadFaces;
315  }
316 }
317 
318 void FaceEnumeration::save(std::ostream& this_stream, const std::vector< std::vector< ListOfFaces > >& latt) {
319  unsigned int allSizes = 0;
320  std::vector< std::vector< ListOfFaces > >::const_iterator iteF;
321  for (iteF=latt.begin(); iteF!=latt.end(); ++iteF) {
322  allSizes = allSizes + iteF->size();
323  }
324  // Don't add the empty polytope and the total polytope.
325  //allSizes = allSizes + 2;
326  //this_ostream << "FaceEnumeration::printFacesWithFacets, total number of elements = " << allSizes << std::endl;
327  unsigned int spaceDimension = Rn::getDimension();
328  unsigned int totalNumberOfFaces = allSizes;
329  this_stream << "# Dimension LatticeSize" << std::endl;
330  this_stream << spaceDimension << " ";
331  this_stream << totalNumberOfFaces << std::endl;
332  unsigned dimReadFaces = 0;
333  for (iteF=latt.begin(); iteF!=latt.end(); ++iteF) {
334  std::vector< ListOfFaces >::const_iterator iteFF;
335  for (iteFF=iteF->begin(); iteFF!=iteF->end(); ++iteFF) {
336  this_stream << dimReadFaces << " " << iteFF->size() << " ";
337  ListOfFaces::const_iterator iteFFF;
338  for (iteFFF=iteFF->begin(); iteFFF!=iteFF->end(); ++iteFFF)
339  this_stream << *iteFFF << " ";
340  this_stream << std::endl;
341  }
342  ++dimReadFaces;
343  }
344 }
345 
346 MinkowskiSum::MinkowskiSum(const std::vector< boost::shared_ptr<Polytope_Rn> >& arrayOfPolytopes, boost::shared_ptr<Polytope_Rn>& C) {
347 
348  boost::shared_ptr<Polytope_Rn> currentSum = *(arrayOfPolytopes.begin());
349  boost::shared_ptr<Polytope_Rn> A = currentSum;
350  std::vector< boost::shared_ptr<Generator_Rn> > listOfGenerators_A, listOfGenerators_B, listOfGenerators_C;
351  std::vector< boost::shared_ptr<PolyhedralCone_Rn> > listOfDualCones_A, listOfDualCones_B, listOfDualCones_C;
352  // Build the list of vertices and dual cones for the first operand.
353  std::vector< std::vector<unsigned int> > neighboursA(A->numberOfGenerators());
354  A->fillIrredundantNeighbourMatrix(neighboursA);
355  {for (unsigned int i=0; i<A->numberOfGenerators(); ++i) {
356  listOfGenerators_A.push_back(A->getGenerator(i));
357  const boost::shared_ptr<PolyhedralCone_Rn>& cone_a = A->getPrimalCone(i, neighboursA[i]);
358  listOfDualCones_A.push_back( cone_a->computeDualPolyhedralCone() );
359  }}
360  {
361  std::vector< boost::shared_ptr<Polytope_Rn> >::const_iterator itePol;
362  for (itePol = arrayOfPolytopes.begin()+1; itePol != arrayOfPolytopes.end(); ++itePol) {
363  boost::shared_ptr<Polytope_Rn> B = *itePol;
364  std::vector< std::vector<unsigned int> > neighboursB(B->numberOfGenerators());
365  B->fillIrredundantNeighbourMatrix(neighboursB);
366  {for (unsigned int i=0; i<B->numberOfGenerators(); ++i) {
367  listOfGenerators_B.push_back(B->getGenerator(i));
368  const boost::shared_ptr<PolyhedralCone_Rn>& cone_b = B->getPrimalCone(i, neighboursB[i]);
369  listOfDualCones_B.push_back( cone_b->computeDualPolyhedralCone() );
370  }}
371  _A2C.resize(listOfGenerators_A.size());
372  _B2C.resize(listOfGenerators_B.size());
374  _MinkowskiDecomposition.clear();
375  computeCommonRefinement(listOfGenerators_A, listOfGenerators_B, listOfGenerators_C, listOfDualCones_A, listOfDualCones_B, listOfDualCones_C);
376  listOfDualCones_A.clear();
377  listOfDualCones_A.swap(listOfDualCones_C);
378  listOfGenerators_A.clear();
379  listOfGenerators_A.swap(listOfGenerators_C);
380  listOfGenerators_C.clear();
381  listOfGenerators_B.clear();
382  listOfDualCones_C.clear();
383  listOfDualCones_B.clear();
384  }
385  }
386  // The global common refinement is in A now.
387  MinkowskiSum globalSum;
388  globalSum._sum = C;
389  globalSum._A2C = _A2C;
390  globalSum._B2C = _B2C;
391  globalSum._NF_Cones = listOfDualCones_A;
392  globalSum._NF_Vertices = listOfGenerators_A;
395  // Build the final sum.
396  globalSum.processNormalFan2();
397 }
398 
400  const std::vector< boost::shared_ptr<Generator_Rn> >& listOfGenerators_A,
401  const std::vector< boost::shared_ptr<Generator_Rn> >& listOfGenerators_B,
402  std::vector< boost::shared_ptr<Generator_Rn> >& listOfGenerators_C,
403  const std::vector< boost::shared_ptr<PolyhedralCone_Rn> >& listOfDualCones_A,
404  const std::vector< boost::shared_ptr<PolyhedralCone_Rn> >& listOfDualCones_B,
405  std::vector< boost::shared_ptr<PolyhedralCone_Rn> >& listOfDualCones_C) {
406  if (listOfGenerators_A.size()==0 || listOfGenerators_B.size()==0)
407  throw std::domain_error("MinkowskiSum::computeCommonRefinement() cannot work without vertices.");
408  unsigned int RnDIM = Rn::getDimension();
409  std::vector< boost::shared_ptr<Generator_Rn> >::const_iterator LVX_A, LVX_B;
410  std::vector< boost::shared_ptr<PolyhedralCone_Rn> >::const_iterator LPC_A, LPC_B;
411  unsigned int minkowskiVertexNumber=0;
412  {for (LPC_B=listOfDualCones_B.begin(), LVX_B=listOfGenerators_B.begin(); LPC_B!=listOfDualCones_B.end(); ++LPC_B, ++LVX_B) {
413  boost::shared_ptr<PolyhedralCone_Rn> Cb = *(LPC_B);
414  {for (LPC_A=listOfDualCones_A.begin(), LVX_A=listOfGenerators_A.begin(); LPC_A!=listOfDualCones_A.end(); ++LPC_A, ++LVX_A) {
415  unsigned int a_i = LPC_A-listOfDualCones_A.begin();
416  unsigned int b_j = LPC_B-listOfDualCones_B.begin();
417  boost::shared_ptr<PolyhedralCone_Rn> Ca = *(LPC_A);
418 #ifdef DEBUG
419  // std::cout << "=== Cone from A number " << LPC_A - listOfDualCones_A.begin() << std::endl;
420  // std::cout << "=== Cone from B number " << LPC_B - listOfDualCones_B.begin() << std::endl;
421  // std::ostringstream stream_A_;
422  // stream_A_ << "EX/ConeA";
423  // stream_A_ << LPC_A - listOfDualCones_A.begin();
424  // stream_A_ << ".pcon";
425  // std::string coneAfile_ = stream_A_.str();
426  // // Primal cones
427  // IO_Polytope::save(coneAfile_, *LPC_A);
428  // (*LPC_A)->checkTopologyAndGeometry();
429  // std::ostringstream stream_B_;
430  // stream_B_ << "EX/ConeB";
431  // stream_B_ << LPC_B - listOfDualCones_B.begin();
432  // stream_B_ << ".pcon";
433  // std::string coneBfile_ = stream_B_.str();
434  // IO_Polytope::save(coneBfile_, *LPC_B);
435  // (*LPC_B)->checkTopologyAndGeometry();
436 #endif
437  boost::shared_ptr<PolyhedralCone_Rn> intersectionCone;
438  intersectionCone.reset(new PolyhedralCone_Rn());
439 #ifdef DEBUG
440  std::cout << "=== Cone from A number " << a_i << std::endl;
441  std::cout << "=== Cone from B number " << b_j << std::endl;
442  std::ostringstream stream_A;
443  stream_A << "EX/ConeA";
444  stream_A << a_i;
445  stream_A << ".pcon";
446  std::string coneAfile = stream_A.str();
447  IO_Polytope::save(coneAfile, Ca);
448  Ca->checkTopologyAndGeometry();
449  std::ostringstream stream_B;
450  stream_B << "EX/ConeB";
451  stream_B << b_j;
452  stream_B << ".pcon";
453  std::string coneBfile = stream_B.str();
454  IO_Polytope::save(coneBfile, Cb);
455  Cb->checkTopologyAndGeometry();
456 #endif
457  // Fill the data structures.
458  int truncationStep = Ca->numberOfHalfSpaces();
460  for (iteHSA.begin(); iteHSA.end()!=true; iteHSA.next())
461  intersectionCone->addHalfSpace(iteHSA.current());
463  for (iteGNA.begin(); iteGNA.end()!=true; iteGNA.next()) {
464  // Make a deep copy of each generator
465  boost::shared_ptr<Generator_Rn> gn(new Generator_Rn( *(iteGNA.current()) ));
466  intersectionCone->addGenerator(gn);
467  }
469  for (iteHSB.begin(); iteHSB.end()!=true; iteHSB.next())
470  intersectionCone->addHalfSpace(iteHSB.current());
471  // Compute the intersection between the two polyhedral cones.
472  //bool notEmpty = intersectionCone->truncate(truncationStep);
473  //std::cout << iteHS.current()->getConstant() << "\t";
475  lexmin_ite(intersectionCone->getListOfHalfSpaces());
476  //NoRedundancyProcessing< boost::shared_ptr<PolyhedralCone_Rn> > NRP;
477  //StrongRedundancyProcessing< boost::shared_ptr<PolyhedralCone_Rn> > NRP(intersectionCone->neigbourhoodCondition());
479  boost::shared_ptr<PolyhedralCone_Rn>,
481  //NoRedundancyProcessing< boost::shared_ptr<PolyhedralCone_Rn> > >
482  //StrongRedundancyProcessing< boost::shared_ptr<PolyhedralCone_Rn> > >
483  DD(intersectionCone, lexmin_ite, truncationStep);
484  bool notEmpty = !DD.getIsEmpty();
485 #ifdef DEBUG
486  std::cout << "@@@ nbEDG=" << intersectionCone->numberOfGenerators() << "( ";
487 #endif
488  // The second test is necessary when dealing with parallelism.
489  if (notEmpty == true && intersectionCone->numberOfGenerators() >= RnDIM) {
490  listOfDualCones_C.push_back(intersectionCone);
491  boost::shared_ptr<Generator_Rn> VX(new Generator_Rn(RnDIM));
492  VX->makeSum(*LVX_A, *LVX_B);
493 #ifdef DEBUG
494  for (unsigned int k=0; k<RnDIM; k++)
495  std::cout << (*LVX_A)->getCoordinate(k) << "+" << (*LVX_B)->getCoordinate(k) << "=" << VX->getCoordinate(k) << "\t";
496  //unsigned int u=LPC_A.currentIteratorNumber();
497  //unsigned int v=LPC_B.currentIteratorNumber();
498  //std::ostringstream stream_C;
499  //stream_C << "EX_2/ConeC";
500  //stream_C << minkowskiVertexNumber;
501  //stream_C << "--";
502  //stream_C << u;
503  //stream_C << "_";
504  //stream_C << v;
505  //stream_C << ".pcon";
506  //std::string coneCfile = stream_C.str();
507  //intersectionCone->checkTopologyAndGeometry();
508  //IO_Polytope::save(coneCfile, intersectionCone);
509 #endif
510  listOfGenerators_C.push_back(VX);
511  // Now store the bijection (a_i, b_j) <-> c_k
512  _MinkowskiDecomposition.push_back( std::make_pair(a_i, b_j) );
513  _MinkowskiDecompositionOK.push_back(true);
514  // Now write the connection between a_i and c_k and also between b_j and c_k.
515  _A2C[a_i].push_back(minkowskiVertexNumber);
516  _B2C[b_j].push_back(minkowskiVertexNumber);
517  ++minkowskiVertexNumber;
518  }
519 #ifdef DEBUG
520  std::cout << ")" << std::endl;
521 #endif
522  }}
523  }}
524 }
525 
526 boost::shared_ptr<Polytope_Rn> MinkowskiSum::compute() {
527  if (_firstOperand->numberOfGenerators()==0 || _firstOperand->numberOfHalfSpaces()==0 ||
528  _secondOperand->numberOfGenerators()==0 || _secondOperand->numberOfHalfSpaces()==0)
529  throw std::domain_error("MinkowskiSum::compute() needs two double-description polytopes i.e. with both vertices and half-spaces.");
530  if (_firstOperand->dimension() != _secondOperand->dimension())
531  throw std::domain_error("MinkowskiSum::compute() needs two same dimension polytopes.");
532 
533  unsigned int lowerBoundIndex1, lowerBoundIndex2, upperBoundIndex1, upperBoundIndex2;
534  double lowerBoundValue = std::numeric_limits< double >::max();
535  double upperBoundValue = std::numeric_limits< double >::min();
536  unsigned int nbVtcesA = _firstOperand->numberOfGenerators();
537  unsigned int nbVtcesB = _secondOperand->numberOfGenerators();
538  if (_firstOperand->dimension() == 1) {
539  // Special case when we work in R.
540  {
541  for (unsigned int i=0; i<nbVtcesA; ++i) {
542  for (unsigned int j=0; j<nbVtcesB; ++j) {
543  if (_firstOperand->getGenerator(i)->getCoordinate(0) + _secondOperand->getGenerator(j)->getCoordinate(0) < lowerBoundValue) {
544  lowerBoundValue = _firstOperand->getGenerator(i)->getCoordinate(0) + _secondOperand->getGenerator(j)->getCoordinate(0);
545  lowerBoundIndex1 = i;
546  lowerBoundIndex2 = j;
547  }
548  if (_firstOperand->getGenerator(i)->getCoordinate(0) + _secondOperand->getGenerator(j)->getCoordinate(0) > upperBoundValue) {
549  upperBoundValue = _firstOperand->getGenerator(i)->getCoordinate(0) + _secondOperand->getGenerator(j)->getCoordinate(0);
550  upperBoundIndex1 = i;
551  upperBoundIndex2 = j;
552  }
553  }
554  }
555  }
556  boost::shared_ptr<Generator_Rn> VX_u(new Generator_Rn(1)), VX_l(new Generator_Rn(1));
557  VX_u->makeSum(_firstOperand->getGenerator(upperBoundIndex1), _secondOperand->getGenerator(upperBoundIndex2));
558  VX_l->makeSum(_firstOperand->getGenerator(lowerBoundIndex1), _secondOperand->getGenerator(lowerBoundIndex2));
559  boost::shared_ptr<HalfSpace_Rn> HS_u(new HalfSpace_Rn(1)), HS_l(new HalfSpace_Rn(1));
560  HS_u->setConstant( _firstOperand->getGenerator(upperBoundIndex1)->getCoordinate(0) + _secondOperand->getGenerator(upperBoundIndex2)->getCoordinate(0));
561  HS_l->setConstant(-_firstOperand->getGenerator(lowerBoundIndex1)->getCoordinate(0) - _secondOperand->getGenerator(lowerBoundIndex2)->getCoordinate(0));
562  HS_u->setCoefficient(0,-1.);
563  HS_l->setCoefficient(0, 1.);
564  VX_u->setFacet(HS_u);
565  VX_l->setFacet(HS_l);
566  _sum->addGenerator(VX_u);
567  _sum->addGenerator(VX_l);
568  _sum->addHalfSpace(HS_u, false);
569  _sum->addHalfSpace(HS_l, false);
570  return _sum;
571  }
572 
573  //minkowskiVertices(i,j)==1 <=> a_i + b_j is a Minkowski vertex.
574  //MinkowskiDecomposition[k] = (a_i,b_j) <=> c_k = a_i + b_j is a Minkowski vertex.
575  //_neighboursA(a_i,a_j)==1 <=> a_i R a_j
576  //_neighboursB(b_i,b_j)==1 <=> b_u R b_v
577  //_neighboursA.resize(_firstOperand->numberOfGenerators());
578  //_neighboursB.resize(_secondOperand->numberOfGenerators());
579  // _firstOperand->fillNeighbourMatrix(_neighboursA, RnDIM-1);
580  //_secondOperand->fillNeighbourMatrix(_neighboursB, RnDIM-1);
581  //std::cout << "_neighboursA: " << std::endl;
582  //{for (unsigned int i=0; i<_neighboursA.size(); ++i) {
583  //std::cout << i << ": ";
584  //std::copy(_neighboursA[i].begin(), _neighboursA[i].end(), std::ostream_iterator<unsigned int>(std::cout, " ") );
585  //std::cout << std::endl;
586  //}}
587  //std::cout << "_neighboursB: " << std::endl;
588  //{for (unsigned int i=0; i<_neighboursB.size(); ++i) {
589  //std::cout << i << ": ";
590  //std::copy(_neighboursB[i].begin(), _neighboursB[i].end(), std::ostream_iterator<unsigned int>(std::cout, " ") );
591  //std::cout << std::endl;
592  //}}
593 
594  // Give the relation between a vertex of A and all of its associated Minkowski vertices i.e. its polyhedrical cap
595  // _A2C[i] = [ c_u, c_v, ... ] }
596  // } => c_u = a_i + b_j
597  // _B2C[j] = [ c_u, c_w, ... ] }
598  _A2C.resize(_firstOperand->numberOfGenerators());
599  _B2C.resize(_secondOperand->numberOfGenerators());
600  std::vector< boost::shared_ptr<Generator_Rn> > listOfGenerators_A;
601  std::vector< boost::shared_ptr<Generator_Rn> > listOfGenerators_B;
602  std::vector< boost::shared_ptr<PolyhedralCone_Rn> > listOfDualCones_A;
603  std::vector< boost::shared_ptr<PolyhedralCone_Rn> > listOfDualCones_B;
604  std::vector< std::vector<unsigned int> > neighboursA(_firstOperand->numberOfGenerators());
605  _firstOperand->fillIrredundantNeighbourMatrix(neighboursA);
606  {for (unsigned int i=0; i<_firstOperand->numberOfGenerators(); ++i) {
607  listOfGenerators_A.push_back(_firstOperand->getGenerator(i));
608  const boost::shared_ptr<PolyhedralCone_Rn>& cone_a = _firstOperand->getPrimalCone(i, neighboursA[i]);
609  listOfDualCones_A.push_back( cone_a->computeDualPolyhedralCone() );
610  }}
611  std::vector< std::vector<unsigned int> > neighboursB(_secondOperand->numberOfGenerators());
612  _secondOperand->fillIrredundantNeighbourMatrix(neighboursB);
613  {for (unsigned int i=0; i<_secondOperand->numberOfGenerators(); ++i) {
614  listOfGenerators_B.push_back(_secondOperand->getGenerator(i));
615  const boost::shared_ptr<PolyhedralCone_Rn>& cone_b = _secondOperand->getPrimalCone(i, neighboursB[i]);
616  listOfDualCones_B.push_back( cone_b->computeDualPolyhedralCone() );
617  }}
618 
619  computeCommonRefinement(listOfGenerators_A, listOfGenerators_B, _NF_Vertices, listOfDualCones_A, listOfDualCones_B, _NF_Cones);
620 
622 
623  //_sum->checkTopologyAndGeometry();
624  return _sum;
625 }
626 
628 {
629  unsigned int RnDIM=Rn::getDimension();
630  double TOL=Rn::getTolerance();
631 
632  boost::numeric::ublas::matrix<double> matOfVtx(_NF_Vertices.size(), RnDIM);
633  {
634  unsigned int vtxNumber=0;
635  std::vector< boost::shared_ptr<Generator_Rn> >::iterator iteVX2;
636  {for (iteVX2 = _NF_Vertices.begin(); iteVX2!=_NF_Vertices.end(); ++iteVX2) {
637  boost::numeric::ublas::matrix_row< boost::numeric::ublas::matrix<double> > matRow(matOfVtx, vtxNumber);
638  std::copy( (*iteVX2)->begin(), (*iteVX2)->end(), matRow.begin());
639  ++vtxNumber;
640  }}
641  }
642  std::vector< std::vector< unsigned int > > VerticesPerFacet;
643  // To count the total number of edges
644  std::vector< boost::shared_ptr<HalfSpace_Rn> > setOfAllHalfSpaces;
645  std::vector< boost::shared_ptr<Generator_Rn> >::iterator iteVX = _NF_Vertices.begin();
646  std::vector< boost::shared_ptr<PolyhedralCone_Rn> >::iterator itePC = _NF_Cones.begin();
647  {for (; itePC!=_NF_Cones.end(); ++itePC, ++iteVX) {
648  // The big job begins
649  {for (unsigned int u=0; u<(*itePC)->numberOfGenerators(); ++u) {
650  // Build the corresponding half-space.
651  boost::shared_ptr<HalfSpace_Rn> HS;
652  HS.reset(new HalfSpace_Rn(RnDIM));
653  double sum=0.;
654  // The normal vector
655  for (unsigned int coord_count=0; coord_count<RnDIM; coord_count++) {
656  double this_coord = (*itePC)->getGenerator(u)->getCoordinate(coord_count);
657  //HYP->setCoefficient(coord_count, iteEDG.current()->getCoordinate(coord_count));
658  HS->setCoefficient(coord_count, this_coord);
659  sum = sum + this_coord*(*iteVX)->getCoordinate(coord_count);
660  }
661  HS->setConstant(-sum);
662  // Prepare the array of vertices IN/ON.
663  std::vector< unsigned int > vtxStates;
664  double halfSpaceNorm = std::inner_product(HS->begin(), HS->end(), HS->begin(), 0.);
665  halfSpaceNorm = sqrt(halfSpaceNorm);
666  // Now iterate on the list of vertices to classify them.
667  boost::numeric::ublas::vector<double> dist2Hyp = prod(matOfVtx, HS->vect());
668  // Possible future optimization in high dimensions
669  //boost::numeric::ublas::vector<double> dist2Hyp(NF_Vertices.size());
670  //axpy_prod(matOfVtx, HS->vect(), dist2Hyp, true);
671  boost::numeric::ublas::scalar_vector<double> scalsum(_NF_Vertices.size(),sum);
672  dist2Hyp = dist2Hyp - scalsum;
673  dist2Hyp = dist2Hyp / halfSpaceNorm;;
674  {for (unsigned int vtxNumber2=0; vtxNumber2<dist2Hyp.size(); ++vtxNumber2) {
675  if (dist2Hyp(vtxNumber2) > TOL) {
676  // Nothing to do !
677  }
678  //else if (distanceToHyperplane < -TOL) {
679  //std::cerr.precision(15);
680  //std::cerr << "distanceToHyperplane=" << distanceToHyperplane;
681  //std::cerr << std::endl;
682  //HS->dump(std::cerr);
683  //std::cerr << std::endl;
684  //(*iteVX2)->dump(std::cerr);
685  //std::cerr << std::endl;
686  //throw std::domain_error("Polytope_Rn::processNormalFan2() current vertex is out !");
687  //}
688  else {
689  vtxStates.push_back(vtxNumber2);
690  }
691  }}
692  // Now all the states are set for this current half-space.
693 
694  bool inserted=false;
695  {for (unsigned int i=0; i<VerticesPerFacet.size() && inserted==false; ++i) {
696  if (VerticesPerFacet[i].size() == vtxStates.size()) {
697  if (VerticesPerFacet[i] == vtxStates)
698  inserted = true;
699  }
700  else if (VerticesPerFacet[i].size() > vtxStates.size()) {
701  if (std::includes(VerticesPerFacet[i].begin(), VerticesPerFacet[i].end(), vtxStates.begin(), vtxStates.end()) == true) {
702  // No need to do anything as the current set of
703  // generators is included in the set number j.
704  //std::cout << "false1 (size=" << i << ")" << std::endl;
705  inserted = true;
706  }
707  }
708  else {
709  if (std::includes(vtxStates.begin(), vtxStates.end(), VerticesPerFacet[i].begin(), VerticesPerFacet[i].end()) == true) {
710  VerticesPerFacet[i] = vtxStates;
711  setOfAllHalfSpaces[i] = HS;
712  inserted = true;
713  // Do not return yet as we could need to erase another cell in the array.
714  }
715  }
716  }}
717  if (inserted == false) {
718  VerticesPerFacet.push_back(vtxStates);
719  setOfAllHalfSpaces.push_back(HS);
720  //std::cout << "inserted at the end (" << VerticesPerFacet.size() << ")" << std::endl;
721  }
722 
723  }} // {for (unsigned int u=0; u<(*itePC)->numberOfGenerators(); ++u) {
724  }} // {for (; itePC!=NF_Cones.end(); ++itePC, ++iteVX) {
725 
726  // Last job: reconstruct the polytope
727  unsigned int vtxNb=0;
728  iteVX=_NF_Vertices.begin();
729  while (iteVX != _NF_Vertices.end()) {
730  // We insert a vertex only if it has the correct number of half-spaces.
731  // This is due to the fact that some dual cones have the right number of edges
732  // but in fact are "flat" numerically speaking so in the reduction process they
733  // "lose" edges and furthermore do not have at least RnDIM edges.
734  bool foundEnoughHS=false;
735  unsigned int nbHS=0;
736  {for (unsigned int i=0; i<VerticesPerFacet.size() && foundEnoughHS==false; ++i) {
737  {for (unsigned int j=0; j<VerticesPerFacet[i].size(); ++j) {
738  if (VerticesPerFacet[i][j] == vtxNb)
739  ++nbHS;
740  if (nbHS >= RnDIM)
741  foundEnoughHS = true;
742  }}
743  }}
744  if (foundEnoughHS == true) {
745  _sum->addGenerator( (*iteVX) );
746  }
747  else {
748  // A very important step if we want to use the array _MinkowskiDecomposition: some dual cones are flat
749  // so they lose edges during the process and have foundEnoughHS to false. So we need to mark them in
750  // the corresponding array.
751  _MinkowskiDecompositionOK[vtxNb] = false;
752  }
753  ++vtxNb;
754  ++iteVX;
755  }
756  {for (unsigned int i=0; i<VerticesPerFacet.size(); ++i) {
757  {for (unsigned int j=0; j<VerticesPerFacet[i].size(); ++j) {
758  // Give the vertex its corresponding facets.
759  _NF_Vertices[ VerticesPerFacet[i][j] ]->setFacet( setOfAllHalfSpaces[i] );
760  }}
761  _sum->addHalfSpace( setOfAllHalfSpaces[i], false);
762  }}
763 }
764 
766 {
767  unsigned int RnDIM=Rn::getDimension();
768  double TOL=Rn::getTolerance();
769  double TOL2=TOL*TOL;
770  // Give the relation between a vertex of A and all of its associated Minkowski vertices i.e. its polyhedrical cap
771  // _A2C[i] = [ c_u, c_v, ... ] }
772  // } => c_u = a_i + b_j
773  // _B2C[j] = [ c_u, c_w, ... ] }
774  // minkowskiVertices(i,j)==1 <=> a_i + b_j is a Minkowski vertex.
775  // MinkowskiDecomposition[k] = (a_i,b_j) <=> c_k = a_i + b_j is a Minkowski vertex.
776  // _neighboursA(a_i,a_j)==1 <=> a_i R a_j
777  // _neighboursB(b_i,b_j)==1 <=> b_u R b_v
778  unsigned int currentNumber=0;
779  std::vector< boost::shared_ptr<HalfSpace_Rn> > setOfAllHalfSpaces;
780  std::vector< boost::shared_ptr<Generator_Rn> >::iterator iteVX = _NF_Vertices.begin();
781  std::vector< boost::shared_ptr<PolyhedralCone_Rn> >::iterator itePC = _NF_Cones.begin();
782  // Map between an edge and its norm
783  std::map< boost::shared_ptr<Generator_Rn>, double > allEdgesNorms;
784  {for (; itePC!=_NF_Cones.end(); ++itePC, ++iteVX) {
785  // Build a half-space from the dual polyhedral cone generator.
786  // So iterate on the list of its edges.
787 
788  // First of all get the ancestors of the current Minkowski vertex
789  unsigned int a_i = _MinkowskiDecomposition[ currentNumber ].first;
790  unsigned int b_j = _MinkowskiDecomposition[ currentNumber ].second;
791  // Now get all of their facet neighbours
792  // Now inspect all the possible combinations to know whether they provide a Minkowski vertex.
793  std::vector< unsigned int > c_kMinkowskiVertices;
794  std::vector< unsigned int >::const_iterator iteNgb;
795  // Now get all a_i neighbours and find their contributions in terms of Minkowski vertices
796  {for (unsigned int j=0; j<_neighboursA[a_i].size(); ++j) {
797  unsigned int a_i_ngb = _neighboursA[a_i][j];
798  {for (unsigned int k=0; k<_A2C[a_i_ngb].size(); ++k) {
799  // Make sure we will not process the current normal fan with itself.
800  if (_A2C[a_i_ngb][k] != currentNumber)
801  c_kMinkowskiVertices.push_back( _A2C[a_i_ngb][k] );
802  }}
803  }}
804  {for (unsigned int i=0; i<_neighboursB[b_j].size(); ++i) {
805  unsigned int b_j_ngb=_neighboursB[b_j][i];
806  {for (unsigned int k=0; k<_B2C[b_j_ngb].size(); ++k) {
807  if (_B2C[b_j_ngb][k] != currentNumber)
808  c_kMinkowskiVertices.push_back( _B2C[b_j_ngb][k] );
809  }}
810  }}
811  //std::copy(c_kMinkowskiVertices.begin(), c_kMinkowskiVertices.end(), std::ostream_iterator<unsigned int>(std::cout, " ") );
812 
813  // The big job begins
814  {for (unsigned int u=0; u<(*itePC)->numberOfGenerators(); ++u) {
815  // Build the corresponding half-space.
816  boost::shared_ptr<HalfSpace_Rn> HS;
817  HS.reset(new HalfSpace_Rn(RnDIM));
818  double sum=0.;
819  // The normal vector
820  for (unsigned int coord_count=0; coord_count<RnDIM; coord_count++) {
821  double this_coord = (*itePC)->getGenerator(u)->getCoordinate(coord_count);
822  //HYP->setCoefficient(coord_count, iteEDG.current()->getCoordinate(coord_count));
823  HS->setCoefficient(coord_count, this_coord);
824  sum = sum + this_coord*(*iteVX)->getCoordinate(coord_count);
825  }
826  HS->setConstant(-sum);
827  const boost::shared_ptr<Generator_Rn>& gn1=(*itePC)->getGenerator(u);
828  double gn1_sum2 = std::inner_product(gn1->begin(), gn1->end(), gn1->begin(), 0.);
829  {for (iteNgb=c_kMinkowskiVertices.begin(); iteNgb!=c_kMinkowskiVertices.end(); ++iteNgb) {
830  // Check all generators of the neighbour cone against the current one.
831  bool check=true;
832  {for (unsigned int v=0; v<_NF_Cones[*iteNgb]->numberOfGenerators() && check==true; ++v) {
833  const boost::shared_ptr<Generator_Rn>& gn2=_NF_Cones[*iteNgb]->getGenerator(v);
834  double scal_prod = std::inner_product(gn1->begin(), gn1->end(), gn2->begin(), 0.);
835  if (scal_prod > 0.) {
836  double coef1 = scal_prod / gn1_sum2;
837  // Check whether the current edge is in the "tube" of the second one, if not switch them.
838  if (gn1->getNormalDistance(gn2, coef1, RnDIM) < TOL2) {
839  // We found a copy of the current edge so remove it from the explored polyhedrical cone.
840  _NF_Cones[*iteNgb]->removeGenerator(v);
841  _NF_Vertices[*iteNgb]->setFacet(HS);
842  check = false;
843  }
844  else if (scal_prod > 0.) {
845  double gn2_sum2 = 0.;
846  // First try to get the norm if it was previously computed
847  std::map< boost::shared_ptr<Generator_Rn>, double >::iterator iteNorm = allEdgesNorms.find( gn2 );
848  if (iteNorm == allEdgesNorms.end())
849  gn2_sum2 = std::inner_product(gn2->begin(), gn2->end(), gn2->begin(), 0.);
850  else
851  gn2_sum2 = iteNorm->second;
852  double coef2 = scal_prod / gn2_sum2;
853  if (gn2->getNormalDistance(gn1, coef2, RnDIM) < TOL2) {
854  _NF_Cones[*iteNgb]->removeGenerator(v);
855  _NF_Vertices[*iteNgb]->setFacet(HS);
856  check = false;
857  if (iteNorm != allEdgesNorms.end())
858  allEdgesNorms.erase(iteNorm);
859  }
860  }
861  }
862  }}
863  }}
864  // Insert the half-space in the polytope list, if not already in,
865  // and insert it into the vertex facet list.
866  (*iteVX)->setFacet(HS);
867  setOfAllHalfSpaces.push_back( HS );
868  // Now remove the current generator as it has become useless.
869  (*itePC)->removeGenerator(u);
870  }} // {for (unsigned int u=0; u<(*itePC)->numberOfGenerators() ; ++u) {
871 
872  // Insert the vertex into the polytope vertex list.
873  _sum->addGenerator( (*iteVX) );
874  ++currentNumber;
875  }} // {for (; itePC!=NF_Cones.end(); ++itePC, ++iteVX) {
876 
877  // Check everything's fine
878  {for (itePC=_NF_Cones.begin(); itePC!=_NF_Cones.end(); ++itePC) {
879  if ((*itePC)->numberOfGenerators() != 0)
880  throw std::domain_error("MinkowskiSum::processNormalFan1() dual cones reduction not operational !");
881  }}
882 
883  // Transfer all half-spaces into the main list.
884  std::vector< boost::shared_ptr<HalfSpace_Rn> >::const_iterator iteHS=setOfAllHalfSpaces.begin();
885  {for (iteHS=setOfAllHalfSpaces.begin(); iteHS!=setOfAllHalfSpaces.end(); ++iteHS) {
886  // Thanks to the previous work we do not need to check.
887  _sum->addHalfSpace( *iteHS, false);
888  }}
889 
890 }
891 
893 {
894  unsigned int RnDIM=Rn::getDimension();
895 
896  std::vector< boost::shared_ptr<Generator_Rn> >::iterator iteVX=_NF_Vertices.begin();
897  std::vector< boost::shared_ptr<PolyhedralCone_Rn> >::iterator itePC=_NF_Cones.begin();
898  for (; itePC!=_NF_Cones.end(); ++itePC, ++iteVX) {
899  // Build a half-space from the dual polyhedral cone generator.
900  // So iterate on the list of its edges.
901 
902  //constIteratorOfListOfGenerators iteEDG(itePC.current()->getListOfGenerators());
903  //for (iteEDG.begin(); iteEDG.end()!=true; iteEDG.next()) {
904  for (unsigned int u=0; u<(*itePC)->numberOfGenerators(); u++) {
905  boost::shared_ptr<HalfSpace_Rn> HS;
906  HS.reset(new HalfSpace_Rn(RnDIM));
907  double sum=0.;
908  // The normal vector
909  for (unsigned int coord_count=0; coord_count<RnDIM; coord_count++) {
910  double this_coord = (*itePC)->getGenerator(u)->getCoordinate(coord_count);
911  //HYP->setCoefficient(coord_count, iteEDG.current()->getCoordinate(coord_count));
912  HS->setCoefficient(coord_count, this_coord);
913  sum = sum + this_coord*(*iteVX)->getCoordinate(coord_count);
914  }
915  HS->setConstant(-sum);
916  // Insert the half-space in the polytope list, if not already in,
917  // and insert it into the vertex facet list.
918  (*iteVX)->setFacet(_sum->addHalfSpace(HS, true));
919  }
920  // Insert the vertex into the polytope vertex list.
921  _sum->addGenerator( (*iteVX) );
922  }
923 
924 }
925 
926 //========================================================================================
927 
930  const std::set< unsigned int >& firstOperandCaps,
931  const std::set< unsigned int >& secondOperandCaps,
932  std::set< unsigned int >& sumCaps) {
933 #ifdef DEBUG
934  std::cout << "PseudoSumWithoutCaps::computeCapHalfSpaces()" << endl;
935 #endif
936  if (_sum->numberOfGenerators()==0)
937  throw std::domain_error("PseudoSumWithoutCaps::computeCapHalfSpaces() We need to compute the Minkowski sum first.");
938 
939  // For each facet of the sum, store its vertices.
940  unsigned int facetNumber=0;
941  std::vector< std::vector<unsigned int> > listOfVerticesPerFacet(_sum->numberOfHalfSpaces());
943  {for (iteHS.begin(); iteHS.end()!=true; iteHS.next()) {
944 #ifdef DEBUG
945  std::cout << "facetNumber=" << facetNumber << ":";
946 #endif
948  {for (iteGN.begin(); iteGN.end()!=true; iteGN.next()) {
949  for (unsigned int i=0; i<iteGN.current()->numberOfFacets(); ++i) {
950  if (iteGN.current()->getFacet(i) == iteHS.current()) {
951  listOfVerticesPerFacet[facetNumber].push_back(iteGN.currentIteratorNumber());
952 #ifdef DEBUG
953  std::cout << " " << iteGN.currentIteratorNumber();
954 #endif
955  }
956  }
957  }}
958  ++facetNumber;
959 #ifdef DEBUG
960  std::cout << endl;
961 #endif
962  }}
963 
964  // Reorder the data structures in the father class.
965  std::vector< std::pair< unsigned int, unsigned int > > thisMinkDecomposition;
966  std::vector< boost::shared_ptr<PolyhedralCone_Rn> > theseNF_Cones;
967  std::vector< boost::shared_ptr<Generator_Rn> > theseNF_Vertices;
968  {for (unsigned int i=0; i<_MinkowskiDecompositionOK.size(); ++i) {
969  if (_MinkowskiDecompositionOK[i] == true) {
970  thisMinkDecomposition.push_back( _MinkowskiDecomposition[i] );
971  theseNF_Vertices.push_back( _NF_Vertices[i] );
972  theseNF_Cones.push_back( _NF_Cones[i] );
973  }
974  }}
975  _MinkowskiDecomposition = thisMinkDecomposition;
976  _NF_Vertices = theseNF_Vertices;
977  _NF_Cones = theseNF_Cones;
978 
979  // Now facet by facet, decompose the Minkowski vertices into vertices of A and B.
980  unsigned int sumFacetNb = 0;
981  std::vector< std::vector<unsigned int> >::const_iterator itVtx = listOfVerticesPerFacet.begin();
982  {for (; itVtx!=listOfVerticesPerFacet.end(); ++itVtx) {
983  std::set< unsigned int > listOfVtxA, listOfVtxB;
984  std::vector<unsigned int>::const_iterator MinkVtx = itVtx->begin();
985 #ifdef DEBUG
986  std::cout << endl << "Compute F_A and F_B for facet " << sumFacetNb << endl;
987 #endif
988  {for (; MinkVtx!=itVtx->end(); ++MinkVtx) {
989  unsigned int MinkNumber = *MinkVtx;
990  listOfVtxA.insert( _MinkowskiDecomposition[MinkNumber].first );
991  listOfVtxB.insert( _MinkowskiDecomposition[MinkNumber].second);
992  }}
993 
994  std::set<unsigned int> listOfFacetsOfVtxA;
995  std::set<unsigned int> tmpInterResForA, tmp2InterResForA;
996  std::set<unsigned int>::const_iterator itVtxNbOperand;
997  itVtxNbOperand = listOfVtxA.begin();
998  for (unsigned int ngb_count=0; ngb_count<_firstOperand->getGenerator(*itVtxNbOperand)->numberOfFacets(); ngb_count++) {
999  boost::shared_ptr<HalfSpace_Rn> Fi = _firstOperand->getGenerator(*itVtxNbOperand)->getFacet(ngb_count);
1000  listOfFacetsOfVtxA.insert(_firstOperand->getHalfSpaceNumber(Fi));
1001  }
1002  //_firstOperand->getGenerator(*itVtxNbOperand)->exportFacets(listOfFacetsOfVtxA);
1003 #ifdef DEBUG
1004  std::cout << "F_A:";
1005  std::cout << " V = {";
1006  std::cout << " " << *itVtxNbOperand;
1007 #endif
1008  tmpInterResForA = listOfFacetsOfVtxA;
1009  itVtxNbOperand++;
1010  {for (; itVtxNbOperand!=listOfVtxA.end(); ++itVtxNbOperand) {
1011 #ifdef DEBUG
1012  std::cout << " " << *itVtxNbOperand;
1013 #endif
1014  std::set<unsigned int> curListOfFacetsOfVtxA;
1015  for (unsigned int ngb_count=0; ngb_count<_firstOperand->getGenerator(*itVtxNbOperand)->numberOfFacets(); ngb_count++) {
1016  boost::shared_ptr<HalfSpace_Rn> Fi = _firstOperand->getGenerator(*itVtxNbOperand)->getFacet(ngb_count);
1017  curListOfFacetsOfVtxA.insert(_firstOperand->getHalfSpaceNumber(Fi));
1018  }
1019  tmp2InterResForA = tmpInterResForA;
1020  tmpInterResForA.clear();
1021  std::set_intersection(
1022  tmp2InterResForA.begin(),
1023  tmp2InterResForA.end(),
1024  curListOfFacetsOfVtxA.begin(),
1025  curListOfFacetsOfVtxA.end(),
1026  std::inserter(tmpInterResForA, tmpInterResForA.end()));
1027  if (listOfFacetsOfVtxA.empty() == true)
1028  throw std::domain_error("PseudoSumWithoutCaps::computeCapHalfSpaces() the i-Face of polytope A has 0 half-space.");
1029  }}
1030 #ifdef DEBUG
1031  std::cout << " }";
1032 #endif
1033  // At this step the half-spaces support of F_A are computed.
1034  std::set<unsigned int> InterResForA;
1035  std::set_intersection(
1036  tmpInterResForA.begin(),
1037  tmpInterResForA.end(),
1038  firstOperandCaps.begin(),
1039  firstOperandCaps.end(),
1040  std::inserter(InterResForA, InterResForA.end()));
1041 #ifdef DEBUG
1042  std::cout << " ; H = { ";
1043  std::copy(InterResForA.begin(), InterResForA.end(), std::ostream_iterator<unsigned int>(std::cout, " ") );
1044  //std::cout << listOfFacetsOfVtxA.size();
1045  std::cout << "}";
1046  std::cout << endl;
1047 #endif
1048 
1049  if (InterResForA.empty() != true)
1050  sumCaps.insert( sumFacetNb );
1051  else {
1053  // 2nd part //
1055  // Get the facets of all the vertices of the j-face in B and intersect them to extract the support.
1056  std::set<unsigned int> listOfFacetsOfVtxB;
1057  std::set<unsigned int> tmpInterResForB, tmp2InterResForB;
1058  itVtxNbOperand = listOfVtxB.begin();
1059  for (unsigned int ngb_count=0; ngb_count<_secondOperand->getGenerator(*itVtxNbOperand)->numberOfFacets(); ngb_count++) {
1060  boost::shared_ptr<HalfSpace_Rn> Fi = _secondOperand->getGenerator(*itVtxNbOperand)->getFacet(ngb_count);
1061  listOfFacetsOfVtxB.insert(_secondOperand->getHalfSpaceNumber(Fi));
1062  }
1063 #ifdef DEBUG
1064  std::cout << "F_B:";
1065  std::cout << " V = {";
1066  std::cout << " " << *itVtxNbOperand;
1067 #endif
1068  tmpInterResForB = listOfFacetsOfVtxB;
1069  itVtxNbOperand++;
1070  {for (; itVtxNbOperand!=listOfVtxB.end(); ++itVtxNbOperand) {
1071 #ifdef DEBUG
1072  std::cout << " " << *itVtxNbOperand;
1073 #endif
1074  std::set<unsigned int> curListOfFacetsOfVtxB;
1075  for (unsigned int ngb_count=0; ngb_count<_secondOperand->getGenerator(*itVtxNbOperand)->numberOfFacets(); ngb_count++) {
1076  boost::shared_ptr<HalfSpace_Rn> Fi = _secondOperand->getGenerator(*itVtxNbOperand)->getFacet(ngb_count);
1077  curListOfFacetsOfVtxB.insert(_secondOperand->getHalfSpaceNumber(Fi));
1078  }
1079  tmp2InterResForB = tmpInterResForB;
1080  tmpInterResForB.clear();
1081  std::set_intersection(
1082  tmp2InterResForB.begin(),
1083  tmp2InterResForB.end(),
1084  curListOfFacetsOfVtxB.begin(),
1085  curListOfFacetsOfVtxB.end(),
1086  std::inserter(tmpInterResForB, tmpInterResForB.end()));
1087  if (listOfFacetsOfVtxB.empty() == true)
1088  throw std::domain_error("PseudoSumWithoutCaps::computeCapHalfSpaces() the j-Face of polytope B has 0 half-space.");
1089  }}
1090 #ifdef DEBUG
1091  std::cout << " }";
1092 #endif
1093  // Now we have all the geometric supports of F_B, see whether there is a cap half-space inside.
1094  std::set<unsigned int> InterResForB;
1095  std::set_intersection(
1096  tmpInterResForB.begin(),
1097  tmpInterResForB.end(),
1098  secondOperandCaps.begin(),
1099  secondOperandCaps.end(),
1100  std::inserter(InterResForB, InterResForB.end()));
1101 #ifdef DEBUG
1102  std::cout << " ; H = { ";
1103  std::copy(InterResForB.begin(), InterResForB.end(), std::ostream_iterator<unsigned int>(std::cout, " ") );
1104  //std::cout << listOfFacetsOfVtxB.size();
1105  std::cout << "}";
1106  std::cout << endl;
1107 #endif
1108 
1109  // If at least one cap half-space is in listOfFacetsOfVtxA or listOfFacetsOfVtxB then the current half-space of the sum is capped too.
1110  if (InterResForB.empty() != true)
1111  sumCaps.insert( sumFacetNb );
1112  }
1113 
1114  sumFacetNb++;
1115  }}
1116 
1117 }
1118 
1119 // Remove the cap half-spaces stored in sets and then truncate again.
1120 boost::shared_ptr<Polytope_Rn> PseudoSumWithoutCaps::rebuildSum(
1121  const std::set<unsigned int>& firstOperandCaps,
1122  const std::set<unsigned int>& secondOperandCaps,
1123  std::set<unsigned int>& newCaps,
1124  double bb_size)
1125 {
1126  if (_sum->numberOfHalfSpaces() == 0 || _sum->numberOfGeneratorsPerFacet() == 0)
1127  throw std::domain_error("PseudoSumWithoutCaps::rebuildSum() _sum is not computed.");
1128 
1129  std::set< unsigned int > sumCaps;
1130  computeCapHalfSpaces(firstOperandCaps, secondOperandCaps, sumCaps);
1131 #ifdef DEBUG
1132  std::cout << "firstOperandCaps=" << firstOperandCaps.size() << std::endl;
1133  std::cout << "secondOperandCaps=" << secondOperandCaps.size() << std::endl;
1134  std::cout << "sumCaps=" << sumCaps.size() << std::endl;
1135 #endif
1136 
1137  // Now remove all cap half-spaces from the current polytope and create another one without them.
1138  boost::shared_ptr<Polytope_Rn> newSum;
1139  newSum.reset(new Polytope_Rn());
1140  newSum->createBoundingBox(bb_size);
1141  std::vector< boost::shared_ptr<HalfSpace_Rn> > tryCapsForNewSum;
1142  // Create the new cap half-spaces.
1143  constIteratorOfListOfGeometricObjects< boost::shared_ptr<HalfSpace_Rn> > iteHS1(newSum->getListOfHalfSpaces());
1144  for (iteHS1.begin(); iteHS1.end()!=true; iteHS1.next()) {
1145  tryCapsForNewSum.push_back(iteHS1.current());
1146  }
1147  // Copy the non cap half-spaces.
1149  for (iteHS2.begin(); iteHS2.end()!=true; iteHS2.next()) {
1150  if (sumCaps.find(iteHS2.currentIteratorNumber()) == sumCaps.end())
1151  newSum->addHalfSpace(iteHS2.current());
1152  }
1153 
1154  // Use a trick based on the size of the bounding box, if it is null consider we do not truncate and return now.
1155  if (bb_size == 0.) {
1156  newCaps = sumCaps;
1157  _sum = newSum;
1158  return newSum;
1159  }
1160 
1161  // Now the truncation.
1162  constIteratorOfListOfGeometricObjects< boost::shared_ptr<HalfSpace_Rn> > lexmin_ite(newSum->getListOfHalfSpaces());
1163  //StrongRedundancyProcessing< boost::shared_ptr<PolyhedralCone_Rn> > NRP(newSum->neigbourhoodCondition());
1164  // The number of facets for a cube.
1165  unsigned int truncationStep = 2*Rn::getDimension();
1167  boost::shared_ptr<PolyhedralCone_Rn>,
1169  //StrongRedundancyProcessing< boost::shared_ptr<PolyhedralCone_Rn> > >
1170  DD(newSum, lexmin_ite, truncationStep);
1171 
1172  // Build the new list of cap half-spaces for _sum
1173  constIteratorOfListOfGeometricObjects< boost::shared_ptr<HalfSpace_Rn> > iteHS3(newSum->getListOfHalfSpaces());
1174  for (iteHS3.begin(); iteHS3.end()!=true; iteHS3.next()) {
1175  std::vector< boost::shared_ptr<HalfSpace_Rn> >::const_iterator iteCaps = tryCapsForNewSum.begin();
1176  for (; iteCaps!=tryCapsForNewSum.end(); ++iteCaps) {
1177  if (iteHS3.current() == *iteCaps) {
1178  newCaps.insert(iteHS3.currentIteratorNumber());
1179  break;
1180  }
1181  }
1182  }
1183  _sum = newSum;
1184 
1185  return newSum;
1186 }
1187 
1188 //=========================================================================
1189 
1191  const boost::shared_ptr<Polytope_Rn>& A,
1192  const boost::shared_ptr<Polytope_Rn>& B,
1193  boost::shared_ptr<Polytope_Rn>& C,
1194  const std::set< unsigned int >& firstOperandCaps,
1195  const std::set< unsigned int >& secondOperandCaps,
1196  std::set< unsigned int >& newCaps,
1197  double bb_size) {
1198 
1199  // Prepare the intersection polytope.
1200  C.reset(new Polytope_Rn());
1201  C->createBoundingBox(bb_size);
1202  std::vector< boost::shared_ptr<HalfSpace_Rn> > RnCaps;
1203  // Get the cube cap half-spaces
1205  for (iteHS0.begin(); iteHS0.end()!=true; iteHS0.next()) {
1206  RnCaps.push_back(iteHS0.current());
1207  }
1208  // Copy the non cap half-spaces of A.
1210  for (iteHS1.begin(); iteHS1.end()!=true; iteHS1.next()) {
1211  if (firstOperandCaps.find(iteHS1.currentIteratorNumber()) == firstOperandCaps.end())
1212  C->addHalfSpace(iteHS1.current());
1213  }
1214  // Copy the non cap half-spaces of B.
1216  for (iteHS2.begin(); iteHS2.end()!=true; iteHS2.next()) {
1217  if (secondOperandCaps.find(iteHS2.currentIteratorNumber()) == secondOperandCaps.end())
1218  C->addHalfSpace(iteHS2.current());
1219  }
1220 
1221  // Now the truncation.
1222  constIteratorOfListOfGeometricObjects< boost::shared_ptr<HalfSpace_Rn> > lexmin_ite(C->getListOfHalfSpaces());
1223  //StrongRedundancyProcessing< boost::shared_ptr<PolyhedralCone_Rn> > NRP(C->neigbourhoodCondition());
1224  // The number of facets for a cube.
1225  unsigned int truncationStep = 2*Rn::getDimension();
1227  boost::shared_ptr<PolyhedralCone_Rn>,
1229  //StrongRedundancyProcessing< boost::shared_ptr<PolyhedralCone_Rn> > >
1230  DD(C, lexmin_ite, truncationStep);
1231 
1232  // Build the new list of cap half-spaces for C
1233  newCaps.clear();
1235  for (iteHS3.begin(); iteHS3.end()!=true; iteHS3.next()) {
1236  std::vector< boost::shared_ptr<HalfSpace_Rn> >::const_iterator iteCaps = RnCaps.begin();
1237  for (; iteCaps!=RnCaps.end(); ++iteCaps) {
1238  if (iteHS3.current() == *iteCaps) {
1239  newCaps.insert(iteHS3.currentIteratorNumber());
1240  break;
1241  }
1242  }
1243  }
1244 }
1245 
1246 //========================================================================================
1247 
1248 int TopGeomTools::Translate(boost::shared_ptr<Polytope_Rn>& pol, const boost::numeric::ublas::vector<double>& v2t) {
1249  if (pol->numberOfGenerators() != 0) {
1251  {for (iteGN.begin(); iteGN.end()!=true; iteGN.next()) {
1252  const boost::shared_ptr<Generator_Rn>& v2_A = iteGN.current();
1253  boost::numeric::ublas::vector<double> coord = v2_A->vect() + v2t;
1254  v2_A->setCoordinates(coord);
1255  }}
1256  }
1257  if (pol->numberOfHalfSpaces() != 0) {
1259  {for (iteHS.begin(); iteHS.end()!=true; iteHS.next()) {
1260  const boost::shared_ptr<HalfSpace_Rn>& hs = iteHS.current();
1261  double prod = std::inner_product(hs->begin(), hs->end(), v2t.begin(), 0.);
1262  hs->setConstant( hs->getConstant()-prod );
1263  }}
1264  }
1265  return 0;
1266 }
1267 
1268 int TopGeomTools::GravityCenter(boost::shared_ptr<Polytope_Rn>& pol, boost::numeric::ublas::vector<double>& gravity_center) {
1269  if (pol->numberOfGenerators() != 0) {
1270  for (unsigned int i=0; i<gravity_center.size (); ++i)
1271  gravity_center(i) = 0.;
1273  {for (iteGN.begin(); iteGN.end()!=true; iteGN.next()) {
1274  gravity_center += iteGN.current()->vect();
1275  }}
1276  gravity_center /= pol->numberOfGenerators();
1277  }
1278  else
1279  throw std::domain_error("TopGeomTools::GravityCenter() the polytope already does not have generators.");
1280  return 0;
1281 }
1282 
1283 int TopGeomTools::computeScalingFactorForInclusion(boost::shared_ptr<Polytope_Rn>& pol1, boost::shared_ptr<Polytope_Rn>& pol2, double& sfactor) {
1284  constIteratorOfListOfGeometricObjects< boost::shared_ptr<HalfSpace_Rn> > iteHS_B(pol2->getListOfHalfSpaces());
1285  double maxDistance = 0.;
1286  double currentConstant = -1.;
1287  {for (iteHS_B.begin(); iteHS_B.end()!=true; iteHS_B.next()) {
1288  double halfSpaceNorm = std::inner_product(iteHS_B.current()->begin(), iteHS_B.current()->end(), iteHS_B.current()->begin(), 0.);
1289  halfSpaceNorm = sqrt(halfSpaceNorm);
1290  constIteratorOfListOfGeometricObjects< boost::shared_ptr<Generator_Rn> > iteGN_A(pol1->getListOfGenerators());
1291  {for (iteGN_A.begin(); iteGN_A.end()!=true; iteGN_A.next()) {
1292  double scalarProduct = std::inner_product(iteGN_A.current()->begin(), iteGN_A.current()->end(), iteHS_B.current()->begin(), 0.);
1293  double distanceToHyperplane = (scalarProduct + iteHS_B.current()->getConstant()) / halfSpaceNorm;
1294  if (distanceToHyperplane < -Rn::getTolerance()) {
1295  // HalfSpace_Rn::hs_OUT
1296  if (fabs(distanceToHyperplane) > maxDistance) {
1297  maxDistance = fabs(distanceToHyperplane);
1298  currentConstant = iteHS_B.current()->getConstant();
1299  }
1300  }
1301  }}
1302  }}
1303  if (fabs(currentConstant) > Rn::getTolerance())
1304  sfactor = (currentConstant + maxDistance) / currentConstant;
1305  else
1306  throw std::domain_error("TopGeomTools::computeScalingFactorForInclusion() pol2 should contain the origin to compute the scaling factor.");
1307 
1308  return 0;
1309 }
1310 
1311 int TopGeomTools::scalingFactor(boost::shared_ptr<Polytope_Rn>& pol, double factor) {
1312  if (fabs(factor) < Rn::getTolerance())
1313  throw std::domain_error("TopGeomTools::scalingFactor() scaling factor too small.");
1314  if (pol->numberOfGenerators() != 0) {
1316  for (iteGN.begin(); iteGN.end()!=true; iteGN.next())
1317  iteGN.current()->scalingFactor(factor);
1318  }
1319  if (pol->numberOfHalfSpaces() != 0) {
1321  for (iteHS.begin(); iteHS.end()!=true; iteHS.next())
1322  iteHS.current()->setConstant(iteHS.current()->getConstant()*factor);
1323  }
1324  return 0;
1325 }
1326 
1327 int TopGeomTools::scalingFactor(boost::shared_ptr<PolyhedralCone_Rn>& pol, double factor) {
1328  if (fabs(factor) < Rn::getTolerance())
1329  throw std::domain_error("TopGeomTools::scalingFactor() scaling factor too small.");
1330  if (pol->numberOfGenerators() != 0) {
1332  for (iteGN.begin(); iteGN.end()!=true; iteGN.next())
1333  iteGN.current()->scalingFactor(factor);
1334  }
1335  if (pol->numberOfHalfSpaces() != 0) {
1337  for (iteHS.begin(); iteHS.end()!=true; iteHS.next())
1338  iteHS.current()->setConstant(iteHS.current()->getConstant()*factor);
1339  }
1340  return 0;
1341 }
1342 
1344  const std::set< unsigned int >& listOfHyperplanes,
1345  const boost::shared_ptr<Polytope_Rn>& original_pol,
1346  boost::shared_ptr<Polytope_Rn>& proj_pol) {
1347  // Here we really need to work with Rn::getDimension()
1348  unsigned int currentDimension = Rn::getDimension();
1349  if (listOfHyperplanes.empty()==true || listOfHyperplanes.size()>Rn::getDimension())
1350  throw std::invalid_argument("TopGeomTools::projectPolytopeOnCanonicalHyperplanes() wrong list of hyperplanes to project");
1351  unsigned int projectedDimension = listOfHyperplanes.size();
1352 
1353  Rn::setDimension(projectedDimension);
1354  proj_pol.reset(new Polytope_Rn());
1355 
1356  std::vector< boost::shared_ptr<Generator_Rn> > newArrayOfGN;
1357  constIteratorOfListOfGeometricObjects< boost::shared_ptr<Generator_Rn> > iteGN(original_pol->getListOfGenerators());
1358  {for (iteGN.begin(); iteGN.end()!=true; iteGN.next()) {
1359  unsigned int j = 0;
1360  boost::shared_ptr<Generator_Rn> VX;
1361  VX.reset(new Generator_Rn(projectedDimension));
1362  for (unsigned int i=1; i<=currentDimension; ++i) {
1363  if (listOfHyperplanes.find(i) != listOfHyperplanes.end()) {
1364  // The direction i is significant so store the corresponding coordinate.
1365  VX->setCoordinate(j, iteGN.current()->getCoordinate(i-1));
1366  ++j;
1367  }
1368  }
1369  bool foundEqual = false;
1370  std::vector< boost::shared_ptr<Generator_Rn> >::const_iterator iteNew = newArrayOfGN.begin();
1371  for ( ; iteNew != newArrayOfGN.end() && foundEqual == false; ++iteNew) {
1372  if (VX->distanceFrom(**iteNew) < Rn::getTolerance())
1373  foundEqual = true;
1374  }
1375  if (foundEqual == false)
1376  newArrayOfGN.push_back( VX );
1377  }}
1378 
1379  std::vector< boost::shared_ptr<Generator_Rn> >::const_iterator iteNew2 = newArrayOfGN.begin();
1380  for ( ; iteNew2 != newArrayOfGN.end(); ++iteNew2)
1381  proj_pol->addGenerator(*iteNew2);
1382 
1383  DoubleDescriptionFromGenerators::Compute(proj_pol, 10000.);
1384  proj_pol->checkTopologyAndGeometry();
1385 
1386  Rn::setDimension(currentDimension);
1387  return 0;
1388 }
1389 
1391  const std::set< unsigned int >& originalSpaceDirections,
1392  unsigned int totalSpaceDimension,
1393  const boost::shared_ptr<Polytope_Rn>& original_polytope,
1394  boost::shared_ptr<PolyhedralCone_Rn>& extruded_polyhedron) {
1395 
1396  unsigned int originalDimension = Rn::getDimension();
1397  if (originalSpaceDirections.empty()==true || originalSpaceDirections.size()>Rn::getDimension())
1398  throw std::invalid_argument("TopGeomTools::extrudeInCanonicalDirections() wrong definition of the original space");
1399 
1400  // Careful as we are going to mix the dimensions of the different spaces.
1401  Rn::setDimension(totalSpaceDimension);
1402  //extruded_polyhedron.reset(new PolyhedralCone_Rn());
1403 
1404  constIteratorOfListOfGeometricObjects< boost::shared_ptr<HalfSpace_Rn> > iteHS(original_polytope->getListOfHalfSpaces());
1405  {for (iteHS.begin(); iteHS.end()!=true; iteHS.next()) {
1406  boost::shared_ptr<HalfSpace_Rn> newHS;
1407  newHS.reset(new HalfSpace_Rn(totalSpaceDimension));
1408  newHS->setConstant(iteHS.current()->getConstant());
1409  unsigned int shift = 0;
1410  for (unsigned int i=1; i<=totalSpaceDimension; ++i) {
1411  // Test whether i belong to the previously referenced directions.
1412  if (originalSpaceDirections.find(i) != originalSpaceDirections.end()) {
1413  newHS->setCoefficient(i-1, iteHS.current()->getCoefficient(i-shift-1));
1414  }
1415  else {
1416  newHS->setCoefficient(i-1, 0.);
1417  ++shift;
1418  }
1419  }
1420  extruded_polyhedron->addHalfSpace(newHS);
1421  }}
1422 
1423  // Back to the previous space
1424  Rn::setDimension(originalDimension);
1425  return 0;
1426 }
1427 
1429  const boost::shared_ptr<Polytope_Rn>& original_pol,
1430  boost::shared_ptr<Polytope_Rn>& polar_pol,
1431  bool forceComputation, double bb_size) {
1432  polar_pol.reset(new Polytope_Rn());
1433  unsigned int dim = original_pol->dimension();
1434  double TOL = Rn::getTolerance();
1435  // In the case where we already have a double description in input but we don't want to recompute anything.
1436  if (original_pol->numberOfGenerators() != 0 && original_pol->numberOfHalfSpaces() != 0 && forceComputation == false) {
1437  std::vector< std::vector< unsigned int > > listOfGeneratorsPerFacet;
1438  original_pol->getGeneratorsPerFacet(listOfGeneratorsPerFacet);
1439  // Convert all generators into facets.
1440  std::vector< boost::shared_ptr<HalfSpace_Rn> > listOfNewHalfSpaces;
1441  std::vector< double > listOfLinearConstraintNorms;
1442  {
1443  constIteratorOfListOfGeometricObjects< boost::shared_ptr<Generator_Rn> > iteGN(original_pol->getListOfGenerators());
1444  {
1445  for (iteGN.begin(); iteGN.end()!=true; iteGN.next()) {
1446  boost::shared_ptr<HalfSpace_Rn> HS;
1447  HS.reset(new HalfSpace_Rn(dim));
1448  HS->setConstant(1.);
1449  boost::numeric::ublas::vector< double >::const_iterator iteCoord = iteGN.current()->begin();
1450  unsigned int coord_count = 0;
1451  {
1452  for ( ; iteCoord != iteGN.current()->end(); ++iteCoord ) {
1453  HS->setCoefficient(coord_count, *iteCoord);
1454  ++coord_count;
1455  }
1456  }
1457  //std::cout << std::endl;
1458  polar_pol->addHalfSpace(HS);
1459  listOfNewHalfSpaces.push_back(HS);
1460  double halfSpaceNorm = std::inner_product(HS->begin(), HS->end(), HS->begin(), 0.);
1461  listOfLinearConstraintNorms.push_back(sqrt(halfSpaceNorm));
1462  }
1463  }
1464  }
1465  // Convert all facets into generators.
1466  {
1467  constIteratorOfListOfGeometricObjects< boost::shared_ptr<HalfSpace_Rn> > iteHS(original_pol->getListOfHalfSpaces());
1468  {
1469  for (iteHS.begin(); iteHS.end()!=true; iteHS.next()) {
1470  if (iteHS.current()->getConstant() < TOL)
1471  throw std::invalid_argument("TopGeomTools::PolarPolytope() the input polytope should contain the origin.");
1472  boost::numeric::ublas::vector<double> copyOfHSCoef(iteHS.current()->vect());
1473  // Scale the hyperplane such as the constant is equal to 1.
1474  copyOfHSCoef = copyOfHSCoef / iteHS.current()->getConstant();
1475  boost::shared_ptr<Generator_Rn> GN;
1476  GN.reset(new Generator_Rn(dim));
1477  GN->setCoordinates(copyOfHSCoef);
1478  unsigned int gnNb = iteHS.currentIteratorNumber();
1479  {
1480  unsigned int nbON = 0;
1481  bool pointIsOUT = false;
1482  for (unsigned int u=0; u<polar_pol->numberOfHalfSpaces(); ++u) {
1483  // We need to know first if this facet is supposed to be part of this vertex or if it will be connected due to the polarity process (see further).
1484  bool isRegularFacet = false;
1485  // Remember that through the polarity, listOfGeneratorsPerFacet actually means listOfFacetsPerGenerator.
1486  if (std::find(listOfGeneratorsPerFacet[gnNb].begin(), listOfGeneratorsPerFacet[gnNb].end(), u) != listOfGeneratorsPerFacet[gnNb].end() )
1487  isRegularFacet = true;
1488  HalfSpace_Rn::State currentState = polar_pol->checkPoint(GN, listOfNewHalfSpaces[u], listOfLinearConstraintNorms[u]);
1489  if (currentState == HalfSpace_Rn::hs_ON) {
1490  // If this facet was not supposed to be connected to this current vertex the question is: do we need to connect it artificially?
1491  // It might be due to the fact that moving from a polytope to its polar, the pair (V_i, F_j) is going to be turned into (V_j, F_i)
1492  // and that norm_2(F_i) could be very different from norm_2(F_j). In that case, it might have an influence on the distance
1493  // computations i.e. dist(V_i, F_j) is very different from dist(V_j, F_i).
1494  GN->setFacet( listOfNewHalfSpaces[u] );
1495  if (isRegularFacet == true)
1496  nbON++;
1497  }
1498  else if (currentState == HalfSpace_Rn::hs_OUT) {
1499  if (isRegularFacet == true)
1500  pointIsOUT = true;
1501  }
1502  else if (currentState == HalfSpace_Rn::hs_IN) {
1503  // Test whether the facet should be added anyway as it could be theoritically connected to the vertex.
1504  if (isRegularFacet == true)
1505  GN->setFacet( listOfNewHalfSpaces[u] );
1506  }
1507  }
1508  // Do we need to optimize the vertex location?
1509  if (pointIsOUT == true || nbON < dim) {
1511  // Shape healing //
1513  // In that case readjust the vertex geometric location performing the intersection of dim plane supports.
1514  boost::numeric::ublas::matrix<double> A(dim,dim);
1515  boost::numeric::ublas::vector<double> x(dim);
1516  boost::numeric::ublas::permutation_matrix<double> pm(A.size1());
1517  {
1518  for (unsigned int j=0; j<dim; ++j) {
1519  const boost::numeric::ublas::vector<double>& hyperplane = listOfNewHalfSpaces[ listOfGeneratorsPerFacet[gnNb][j] ]->vect();
1520  boost::numeric::ublas::matrix_row< boost::numeric::ublas::matrix<double> > A_row_j(A, j);
1521  A_row_j = hyperplane;
1522  x(j) = -listOfNewHalfSpaces[ listOfGeneratorsPerFacet[gnNb][j] ]->getConstant();
1523  }
1524  }
1525  // Perform LU-factorization
1526  int res = boost::numeric::ublas::lu_factorize(A, pm);
1527  if (res == 0)
1528  boost::numeric::ublas::lu_substitute(A, pm, x);
1529  GN->setCoordinates(x);
1530  }
1531  }
1532  polar_pol->addGenerator(GN);
1533  } // for (iteHS.begin(); iteHS.end()!=true; iteHS.next()) {
1534  }
1535  }
1536  return 0;
1537  }
1538  if (original_pol->numberOfGenerators() != 0) {
1539  constIteratorOfListOfGeometricObjects< boost::shared_ptr<Generator_Rn> > iteGN(original_pol->getListOfGenerators());
1540  {
1541  for (iteGN.begin(); iteGN.end()!=true; iteGN.next()) {
1542  boost::shared_ptr<HalfSpace_Rn> HS;
1543  HS.reset(new HalfSpace_Rn(dim));
1544  HS->setConstant(1.);
1545  boost::numeric::ublas::vector< double >::const_iterator iteCoord = iteGN.current()->begin();
1546  unsigned int coord_count = 0;
1547  {
1548  for ( ; iteCoord != iteGN.current()->end(); ++iteCoord ) {
1549  //std::cout << *iteCoord << " ";
1550  HS->setCoefficient(coord_count, *iteCoord);
1551  ++coord_count;
1552  }
1553  }
1554  //std::cout << std::endl;
1555  polar_pol->addHalfSpace(HS);
1556  }
1557  }
1558  // Change the facets order to optimize the computations.
1559  // Comment this line, the idea was to speed up computations for centered polytopes but no operational yet.
1560  //SortHalfSpaces SNV(polar_pol);
1561  //polar_pol->dump(std::cout);
1562  //IO_Polytope::save("Hdesc.ptop", polar_pol);
1563  if (forceComputation == true) {
1564  try {
1565  polar_pol->createBoundingBox(bb_size);
1566  constIteratorOfListOfGeometricObjects< boost::shared_ptr<HalfSpace_Rn> > lexmin_ite(polar_pol->getListOfHalfSpaces());
1567  //StrongRedundancyProcessing< boost::shared_ptr<PolyhedralCone_Rn> > NRP(polar_pol->neigbourhoodCondition());
1568  // The number of facets for a cube.
1569  unsigned int truncationStep = 2*dim;
1571  boost::shared_ptr<PolyhedralCone_Rn>,
1573  //StrongRedundancyProcessing< boost::shared_ptr<PolyhedralCone_Rn> > >
1574  DD(polar_pol, lexmin_ite, truncationStep);
1575  }
1576  catch(invalid_argument& except) {
1577  cerr << "Invalid argument exception in TopGeomTools::PolarPolytope() " << except.what() << endl;
1578  return -1;
1579  }
1580  catch(out_of_range& except) {
1581  cerr << "Out of range exception in TopGeomTools::PolarPolytope() " << except.what() << endl;
1582  return -1;
1583  }
1584  catch(ios_base::failure& except) {
1585  cerr << "In/out exception in TopGeomTools::PolarPolytope() " << except.what() << endl;
1586  return -1;
1587  }
1588  catch(logic_error& except) {
1589  cerr << "Logic error exception in TopGeomTools::PolarPolytope() " << except.what() << endl;
1590  return -1;
1591  }
1592  catch(...) {
1593  cerr << "Unexpected exception caught in TopGeomTools::PolarPolytope() !" << endl;
1594  return -1;
1595  }
1596  }
1597  // Whether there were or not half-spaces, we leave now.
1598  return 0;
1599  }
1600  // At this step we know that generators were not provided.
1601  if (original_pol->numberOfHalfSpaces() != 0) {
1602  constIteratorOfListOfGeometricObjects< boost::shared_ptr<HalfSpace_Rn> > iteHS(original_pol->getListOfHalfSpaces());
1603  {
1604  for (iteHS.begin(); iteHS.end()!=true; iteHS.next()) {
1605  if (iteHS.current()->getConstant() < TOL)
1606  throw std::invalid_argument("TopGeomTools::PolarPolytope() the input polytope should contain the origin.");
1607  boost::numeric::ublas::vector<double> copyOfHSCoef(iteHS.current()->vect());
1608  // Scale the hyperplane such as the constant is equal to 1.
1609  copyOfHSCoef = copyOfHSCoef / iteHS.current()->getConstant();
1610  boost::shared_ptr<Generator_Rn> GN;
1611  GN.reset(new Generator_Rn(dim));
1612  GN->setCoordinates(copyOfHSCoef);
1613  //if (original_pol->numberOfGenerators() != 0) {
1614  //constIteratorOfListOfGeometricObjects< boost::shared_ptr<HalfSpace_Rn> > polar_iteHS(polar_pol->getListOfHalfSpaces());
1615  //{for (polar_iteHS.begin(); polar_iteHS.end()!=true; polar_iteHS.next()) {
1616  //double halfSpaceNorm = std::inner_product(polar_iteHS.current()->begin(), polar_iteHS.current()->end(), polar_iteHS.current()->begin(), 0.);
1617  //halfSpaceNorm = sqrt(halfSpaceNorm);
1618  //double scalarProduct = std::inner_product(GN->begin(), GN->end(), polar_iteHS.current()->begin(), 0.);
1619  //double distanceToHyperplane = (scalarProduct+polar_iteHS.current()->getConstant()) / halfSpaceNorm;
1620  //if (distanceToHyperplane<TOL && distanceToHyperplane>-TOL)
1621  //GN->setFacet(polar_iteHS.current());
1622  //}}
1623  //}
1624  polar_pol->addGenerator(GN);
1625  }
1626  }
1627  }
1628 
1629  return 0;
1630 }
1631 
1632 //========================================================================================
1633 
1634 int DoubleDescriptionFromGenerators::Compute(boost::shared_ptr<Polytope_Rn>& pol, double bb_size) {
1635  unsigned int dim = pol->dimension();
1636  double TOL = Rn::getTolerance();
1637  if (pol->numberOfHalfSpaces() != 0)
1638  throw std::domain_error("DoubleDescriptionFromGenerators::Compute() the polytope already has half-spaces.");
1639  if (pol->numberOfGenerators() == 0)
1640  throw std::domain_error("DoubleDescriptionFromGenerators::Compute() the polytope does not have generators.");
1641  // Step 1: computes the gravity center
1642  // Step 2: translate the polytope to have its gravity center on the origin
1643  // Step 3: turn the V-description polytope into its H-description polar
1644  // Step 4: get the V-description from the H-description polar
1645  // Step 5: get the polar of the polar
1646  // Step 6: translate it back
1647 
1648  // Step 1: compute the gravity center of the cloud of points.
1649  boost::numeric::ublas::vector<double> gravity_center(dim);
1650  TopGeomTools::GravityCenter(pol, gravity_center);
1651 
1652  // Step 2: translate the cloud to have in centered on the origin if it is not already.
1653  //std::cout << "norm_2(gravity_center) = " << norm_2(gravity_center) << std::endl;
1654  if (norm_2(gravity_center) > TOL)
1655  TopGeomTools::Translate(pol, -gravity_center);
1656 
1657  // Step 3: compute the polar H-description and truncate it.
1658  boost::shared_ptr<Polytope_Rn> polar_pol(new Polytope_Rn());
1659  TopGeomTools::PolarPolytope(pol, polar_pol, true, bb_size);
1660  //polar_pol->checkTopologyAndGeometry();
1661 
1662  // Step 4: compute the polar of the polar.
1663  pol.reset(new Polytope_Rn());
1664  TopGeomTools::PolarPolytope(polar_pol, pol, false, bb_size);
1665  //pol->checkTopologyAndGeometry();
1666 
1667  // Step 5: translate it back.
1668  if (norm_2(gravity_center) > TOL)
1669  TopGeomTools::Translate(pol, gravity_center);
1670 
1671  return 0;
1672 }
1673 
1674 //========================================================================================
1675 
1676 // set palette defined ( 0 "#A90D0D", 0.25 "#22A90D", 0.50 "#0DA9A9", 0.75 "#FFFFFF", 1.0 "#C0C0C0" )
1677 // .. # The background color is set first, then the border colors, then the X & Y axis colors, then the plotting colors
1678 // set terminal png size 1280,960 #ffffff #ffffff #ffffff #000000
1679 // set output "biarn.png"
1680 // plot "biarn.dat" using 3:4:(($5)/1000.):6 with circles linecolor palette z fill solid border lt 1 notitle, 'biarn.dat' using ($3):($4):1 with labels notitle;void Visualization::gnuplot2D(const boost::shared_ptr<Polytope_Rn>& polygon, const std::string& name, double col, std::ostream& out) throw (std::domain_error) {
1681 void Visualization::gnuplot2D(const boost::shared_ptr<Polytope_Rn>& polygon, const std::string& name, double col, std::ostream& out) {
1682  if (Rn::getDimension() != 2)
1683  throw std::domain_error("Visualization::gnuplot(std::ostream& out) dimension is not 2 ");
1684  out << "set object " << name << " polygon from ";
1685  boost::shared_ptr<HalfSpace_Rn> oldHS;
1686  boost::shared_ptr<Generator_Rn> startVTX,referenceVTX;
1687  constIteratorOfListOfGeometricObjects< boost::shared_ptr<Generator_Rn> > LVX_A(polygon->getListOfGenerators());
1688  startVTX = LVX_A.current();
1689  std::set< boost::shared_ptr<Generator_Rn> > alreadyProcessedVTX;
1690  {for (LVX_A.begin(); LVX_A.end()!=true; LVX_A.next()) {
1691  if (alreadyProcessedVTX.find(LVX_A.current()) == alreadyProcessedVTX.end()) {
1692  referenceVTX = LVX_A.current();
1693  alreadyProcessedVTX.insert(referenceVTX);
1694  boost::shared_ptr<HalfSpace_Rn> referenceHS = referenceVTX->getFacet(0);
1695  if (referenceHS == oldHS)
1696  referenceHS = referenceVTX->getFacet(1);
1697  // Write the point
1698  out << LVX_A.current()->getCoordinate(0) << "," << LVX_A.current()->getCoordinate(1) << " to ";
1699  constIteratorOfListOfGeometricObjects< boost::shared_ptr<Generator_Rn> > LVX_B(polygon->getListOfGenerators());
1700  {for (LVX_B.begin(); LVX_B.end()!=true; LVX_B.next()) {
1701  if (alreadyProcessedVTX.find(LVX_B.current()) == alreadyProcessedVTX.end()) {
1702  if (referenceHS == LVX_B.current()->getFacet(0)) {
1703  referenceHS = referenceVTX->getFacet(1);
1704  // Write the point
1705  out << LVX_B.current()->getCoordinate(0) << "," << LVX_B.current()->getCoordinate(1) << " to ";
1706  referenceVTX = LVX_B.current();
1707  alreadyProcessedVTX.insert(referenceVTX);
1708  }
1709  else if (referenceHS == LVX_B.current()->getFacet(1)) {
1710  referenceHS = referenceVTX->getFacet(0);
1711  // Write the point
1712  out << LVX_B.current()->getCoordinate(0) << "," << LVX_B.current()->getCoordinate(1) << " to ";
1713  referenceVTX = LVX_B.current();
1714  alreadyProcessedVTX.insert(referenceVTX);
1715  }
1716  }
1717  }}
1718  }
1719  }}
1720  out << startVTX->getCoordinate(0) << "," << startVTX->getCoordinate(1);
1721  out << " lc palette " << col << std::endl;
1722  //set object 1 fc rgb '#000000' fillstyle solid lw 0
1723 }
1724 
1725 
1730  bool operator() (std::pair< double, NormedHS > pt1, std::pair< double, NormedHS > pt2) { return (pt1.first < pt2.first);}
1732 
1733 
1738  bool operator() (std::pair< double, NormedHS > pt1, std::pair< double, NormedHS > pt2) { return (pt1.second.getConstant() < pt2.second.getConstant());}
1740 
1741 
1742 SortHalfSpaces::SortHalfSpaces(boost::shared_ptr<Polytope_Rn>& pol) {
1743  unsigned int RnDIM = pol->dimension();
1744  // Initialize the list of normed vectors.
1745  std::vector< std::pair<double, NormedHS > > listOfNormedVectors;
1746  {
1747  for (unsigned int idx=0; idx<pol->numberOfHalfSpaces(); ++idx) {
1748  double distance = norm_2(pol->getHalfSpace(idx)->vect());
1749  if (distance > 0.000001) {
1750  NormedHS NV(pol->getHalfSpace(idx)->vect() / distance, pol->getHalfSpace(idx)->getConstant() / distance, idx);
1751  listOfNormedVectors.push_back( std::make_pair(-1., NV) );
1752  }
1753  }
1754  }
1755  //
1756  //std::cout << "BEFORE" << std::endl;
1757  //dump(std::cout, listOfNormedVectors);
1758  // Sort normed halfspaces according to the constant, starting with the smallest one.
1759  std::sort(listOfNormedVectors.begin(), listOfNormedVectors.end(), thisSortedNormedVectorWithConstant);
1760  // {
1761  // unsigned int referenceVector = 0;
1762  // unsigned int nbOfElementsToSort = RnDIM-1;
1763  // std::vector< std::pair<double, NormedHS > >::iterator startIte = listOfNormedVectors.begin();
1764  // std::vector< std::pair<double, NormedHS > >::iterator endIte = startIte + nbOfElementsToSort;
1765  // std::vector< std::pair<double, NormedHS > >::iterator subIte;
1766  // while (startIte < listOfNormedVectors.end()) {
1767  // //std::cout << "startIte = " << startIte - listOfNormedVectors.begin() << std::endl;
1768  // //std::cout << " endIte = " << endIte - listOfNormedVectors.begin() << std::endl;
1769  // for (subIte = startIte; subIte<listOfNormedVectors.end(); ++subIte)
1770  // subIte->first = norm_2( subIte->second.getNormedVector() - startIte->second.getNormedVector());
1771  // // First sorting according to the normal.
1772  // std::partial_sort(startIte, endIte, listOfNormedVectors.end(), thisSortedNormedVector);
1773  // // Second sorting according to the second number.
1774  // //std::sort(startIte, endIte, thisSortedNormedVectorWithConstant);
1775  // startIte = endIte + 1;
1776  // endIte = startIte + nbOfElementsToSort;
1777  // if (endIte >= listOfNormedVectors.end())
1778  // endIte = listOfNormedVectors.end() - 1;
1779  // //std::cout << std::endl << "NEXT" << std::endl;
1780  // //dump(std::cout, listOfNormedVectors);
1781  // }
1782  // }
1783 
1784  {
1786  std::vector< std::pair< double, NormedHS > >::iterator thisIte = listOfNormedVectors.begin();
1787  for (; thisIte<listOfNormedVectors.end(); ++thisIte)
1788  listOfHS.push_back( pol->getHalfSpace( thisIte->second.getNumberOfNormedHS() ) );
1789  pol->reset();
1790  pol->setListOfHalfSpaces(listOfHS);
1791  }
1792 }
SortHalfSpaces::SortHalfSpaces
SortHalfSpaces(boost::shared_ptr< Polytope_Rn > &pol)
Definition: PolyhedralAlgorithms_Rn.cpp:1742
HalfSpace_Rn::hs_OUT
@ hs_OUT
Definition: HalfSpace_Rn.h:47
MinkowskiSum::MinkowskiSum
MinkowskiSum()
Sets up the data structure for the computation of the Minkowski sum of two polytopes.
Definition: PolyhedralAlgorithms_Rn.h:143
MinkowskiSum::_neighboursB
std::vector< std::vector< unsigned int > > _neighboursB
Store the neighbours of each vertex of B.
Definition: PolyhedralAlgorithms_Rn.h:246
TopGeomTools::scalingFactor
static int scalingFactor(boost::shared_ptr< Polytope_Rn > &pol, double sfactor)
Multiply a polytope by a given real number.
Definition: PolyhedralAlgorithms_Rn.cpp:1311
listOfGeometricObjects::push_back
void push_back(const GEOMETRIC_OBJECT &gn)
Include a new half space in the list.
Definition: GeometricObjectIterator_Rn.h:47
HalfSpace_Rn::hs_IN
@ hs_IN
Definition: HalfSpace_Rn.h:46
FaceEnumeration::printFacesWithVerticesToSage
void printFacesWithVerticesToSage(std::ostream &this_ostream) const
Definition: PolyhedralAlgorithms_Rn.cpp:226
SortedNormedVectorWithConstant::operator()
bool operator()(std::pair< double, NormedHS > pt1, std::pair< double, NormedHS > pt2)
Definition: PolyhedralAlgorithms_Rn.cpp:1738
Visualization::gnuplot2D
static void gnuplot2D(const boost::shared_ptr< Polytope_Rn > &polygon, const std::string &name, double col, std::ostream &out)
Provide the drwing of polygon under the gnuplot format.
Definition: PolyhedralAlgorithms_Rn.cpp:1681
MinkowskiSum::compute
boost::shared_ptr< Polytope_Rn > compute()
Compute the common refinement of the two operands normal fans and then build the sum.
Definition: PolyhedralAlgorithms_Rn.cpp:526
MinkowskiSum::processNormalFan1
void processNormalFan1()
Do the final job after having intersected all dual cones. The reduction process uses neighbourhood pr...
Definition: PolyhedralAlgorithms_Rn.cpp:765
FaceEnumeration::printFacesWithFacets
void printFacesWithFacets(std::ostream &this_ostream) const
Definition: PolyhedralAlgorithms_Rn.cpp:176
PolyhedralCone_Rn
Model a polyhedral cone using its two equivalent definitions : the convex hull and the half-space int...
Definition: PolyhedralCone_Rn.h:47
thisSortedNormedVectorWithConstant
struct SortedNormedVectorWithConstant thisSortedNormedVectorWithConstant
MinkowskiSum::_neighboursA
std::vector< std::vector< unsigned int > > _neighboursA
Store the neighbours of each vertex of A.
Definition: PolyhedralAlgorithms_Rn.h:243
TopGeomTools::GravityCenter
static int GravityCenter(boost::shared_ptr< Polytope_Rn > &pol, boost::numeric::ublas::vector< double > &gravity_center)
Compute the gravity center of a given polytope.
Definition: PolyhedralAlgorithms_Rn.cpp:1268
MinkowskiSum::_firstOperand
const boost::shared_ptr< Polytope_Rn > _firstOperand
Definition: PolyhedralAlgorithms_Rn.h:228
MinkowskiSum::_NF_Vertices
std::vector< boost::shared_ptr< Generator_Rn > > _NF_Vertices
The list of C vertices.
Definition: PolyhedralAlgorithms_Rn.h:260
MinkowskiSum::_secondOperand
const boost::shared_ptr< Polytope_Rn > _secondOperand
Definition: PolyhedralAlgorithms_Rn.h:229
thisSortedNormedVector
struct SortedNormedVector thisSortedNormedVector
MinkowskiSum::processNormalFan0
void processNormalFan0()
Do the final job after having intersected all dual cones. The reduction process simply compares all d...
Definition: PolyhedralAlgorithms_Rn.cpp:892
MinkowskiSum::processNormalFan2
void processNormalFan2()
Do the final job after having intersected all dual cones. The reduction process builds half-spaces an...
Definition: PolyhedralAlgorithms_Rn.cpp:627
TopGeomTools::computeScalingFactorForInclusion
static int computeScalingFactorForInclusion(boost::shared_ptr< Polytope_Rn > &pol1, boost::shared_ptr< Polytope_Rn > &pol2, double &sfactor)
Multiply a polytope pol1 is not included in in polytope pol2, compute the sclaing factor for pol2 to ...
Definition: PolyhedralAlgorithms_Rn.cpp:1283
FaceEnumeration::_allFacesWithFacets
std::vector< std::vector< ListOfFaces > > _allFacesWithFacets
Definition: PolyhedralAlgorithms_Rn.h:127
FaceEnumeration::ComputeWithFacets
static void ComputeWithFacets(const boost::shared_ptr< Polytope_Rn > &A, FaceEnumeration &FaceEnum)
Definition: PolyhedralAlgorithms_Rn.cpp:54
listOfGeometricObjects
This class is designed to contain the list of all generators or half-spaces representing a polytope o...
Definition: GeometricObjectIterator_Rn.h:40
MinkowskiSum::_MinkowskiDecompositionOK
std::vector< bool > _MinkowskiDecompositionOK
Tell whether _MinkowskiDecomposition had to be considered or not.
Definition: PolyhedralAlgorithms_Rn.h:255
PseudoSumWithoutCaps::rebuildSum
boost::shared_ptr< Polytope_Rn > rebuildSum(const std::set< unsigned int > &firstOperandCaps, const std::set< unsigned int > &secondOperandCaps, std::set< unsigned int > &newCaps, double bb_size=1000.)
Remove the cap half-spaces stored in sets and then truncate again.
Definition: PolyhedralAlgorithms_Rn.cpp:1120
Rn::getDimension
static polito_EXPORT unsigned int getDimension()
Return the dimension of the cartesian space we work in.
Definition: Rn.cpp:29
MinkowskiSum::_sum
boost::shared_ptr< Polytope_Rn > _sum
Definition: PolyhedralAlgorithms_Rn.h:230
PolyhedralAlgorithms_Rn.h
constIteratorOfListOfGeometricObjects::current
const GEOMETRIC_OBJECT current()
Return the current geometric element.
Definition: GeometricObjectIterator_Rn.h:177
FaceEnumeration
Combinatorial face enumeration for polytopes.
Definition: PolyhedralAlgorithms_Rn.h:44
constIteratorOfListOfGeometricObjects::currentIteratorNumber
int currentIteratorNumber() const
Return the current position in the list.
Definition: GeometricObjectIterator_Rn.h:192
FaceEnumeration::_allFacesWithVertices
std::vector< std::vector< ListOfFaces > > _allFacesWithVertices
Definition: PolyhedralAlgorithms_Rn.h:129
SortedNormedVectorWithConstant
Definition: PolyhedralAlgorithms_Rn.cpp:1734
constIteratorOfListOfGeometricObjects::end
bool end() const
Tell whether we have reached the end of the list.
Definition: GeometricObjectIterator_Rn.h:174
HalfSpace_Rn
A half-space whose frontier is a linear (n-1) dimension space. _constant + _coefficients[0]....
Definition: HalfSpace_Rn.h:40
FaceEnumeration::save
static void save(const std::string &filename, const std::vector< std::vector< ListOfFaces > > &latt)
Save the polytope lattice.
Definition: PolyhedralAlgorithms_Rn.cpp:273
MinkowskiSum::_NF_Cones
std::vector< boost::shared_ptr< PolyhedralCone_Rn > > _NF_Cones
The normal fan polyhedrical cones list.
Definition: PolyhedralAlgorithms_Rn.h:258
Rn.h
MinkowskiSum::_B2C
std::vector< std::vector< unsigned int > > _B2C
Store the polyhedrical cap in C of each vertex of B.
Definition: PolyhedralAlgorithms_Rn.h:239
MinkowskiSum::_A2C
std::vector< std::vector< unsigned int > > _A2C
Store the polyhedrical cap in C of each vertex of A.
Definition: PolyhedralAlgorithms_Rn.h:237
TopGeomTools::extrudeInCanonicalDirections
static int extrudeInCanonicalDirections(const std::set< unsigned int > &originalSpaceDirections, unsigned int dimensionOfTotalSpace, const boost::shared_ptr< Polytope_Rn > &original_polytope, boost::shared_ptr< PolyhedralCone_Rn > &extruded_polyhedron)
Compute the extrusion of a polytope belonging to a space S1 into a higher dimension space S2 followin...
Definition: PolyhedralAlgorithms_Rn.cpp:1390
ListOfFaces
std::vector< unsigned int > ListOfFaces
Definition: PolyhedralAlgorithms_Rn.h:40
DoubleDescriptionFromGenerators::Compute
static int Compute(boost::shared_ptr< Polytope_Rn > &pol, double bb_size=1000.)
Use the polarity to get the facets from the generators.
Definition: PolyhedralAlgorithms_Rn.cpp:1634
constIteratorOfListOfGeometricObjects
This class is designed to run the list of all geometric objects representing a polytope.
Definition: GeometricObjectIterator_Rn.h:142
NormedHS
A normed half-space whose frontier is a linear (n-1) dimension space. _constant + _currentNormedVec...
Definition: PolyhedralAlgorithms_Rn.h:407
DoubleDescription
The algorithm implemented here is an incremental algorithm as mentioned in How Good are Convex Hull ...
Definition: DoubleDescription_Rn.h:86
FaceEnumeration::printFacesWithVertices
void printFacesWithVertices(std::ostream &this_ostream) const
Definition: PolyhedralAlgorithms_Rn.cpp:201
Generator_Rn
A n-coordinates generator, which can be a vertex or an edge whether it is contained by a polytope or ...
Definition: Generator_Rn.h:39
HalfSpace_Rn::State
State
Definition: HalfSpace_Rn.h:44
TopGeomTools::PolarPolytope
static int PolarPolytope(const boost::shared_ptr< Polytope_Rn > &original_pol, boost::shared_ptr< Polytope_Rn > &polar_pol, bool forceComputation=true, double bb_size=1000.)
Compute the polar polytope.
Definition: PolyhedralAlgorithms_Rn.cpp:1428
TopGeomTools::projectPolytopeOnCanonicalHyperplanes
static int projectPolytopeOnCanonicalHyperplanes(const std::set< unsigned int > &listOfHyperplanes, const boost::shared_ptr< Polytope_Rn > &original_pol, boost::shared_ptr< Polytope_Rn > &proj_pol)
Compute the projection of a polytope on the intersection of canonical hyperplanes of the shape xi = 0
Definition: PolyhedralAlgorithms_Rn.cpp:1343
constIteratorOfListOfGeometricObjects::begin
void begin()
Move the iterator at the beginning of the list.
Definition: GeometricObjectIterator_Rn.h:150
TopGeomTools::Translate
static int Translate(boost::shared_ptr< Polytope_Rn > &pol, const boost::numeric::ublas::vector< double > &v2t)
Translate a polytope by the given vector.
Definition: PolyhedralAlgorithms_Rn.cpp:1248
MinkowskiSum::_MinkowskiDecomposition
std::vector< std::pair< unsigned int, unsigned int > > _MinkowskiDecomposition
Store the genitors in A and B of each vertex of C.
Definition: PolyhedralAlgorithms_Rn.h:253
MinkowskiSum::computeCommonRefinement
void computeCommonRefinement(const std::vector< boost::shared_ptr< Generator_Rn > > &listOfGenerators_A, const std::vector< boost::shared_ptr< Generator_Rn > > &listOfGenerators_B, std::vector< boost::shared_ptr< Generator_Rn > > &listOfGenerators_C, const std::vector< boost::shared_ptr< PolyhedralCone_Rn > > &listOfDualCones_A, const std::vector< boost::shared_ptr< PolyhedralCone_Rn > > &listOfDualCones_B, std::vector< boost::shared_ptr< PolyhedralCone_Rn > > &listOfDualCones_C)
Just compute the common refinement of the two operands normal fans.
Definition: PolyhedralAlgorithms_Rn.cpp:399
FaceEnumeration::ComputeWithVertices
static void ComputeWithVertices(const boost::shared_ptr< Polytope_Rn > &A, FaceEnumeration &FaceEnum)
Definition: PolyhedralAlgorithms_Rn.cpp:127
HalfSpace_Rn::hs_ON
@ hs_ON
Definition: HalfSpace_Rn.h:45
PseudoSumWithoutCaps::computeCapHalfSpaces
void computeCapHalfSpaces(const std::set< unsigned int > &firstOperandCaps, const std::set< unsigned int > &secondOperandCaps, std::set< unsigned int > &sumCaps)
Return the cap half-spaces of the sum in function of the two operands cap half-spaces.
Definition: PolyhedralAlgorithms_Rn.cpp:929
SortedNormedVector
Definition: PolyhedralAlgorithms_Rn.cpp:1726
Polytope_Rn.h
Rn::setDimension
static polito_EXPORT void setDimension(unsigned int dim)
Set the dimension for the cartesian space we work in.
Definition: Rn.cpp:27
IO_Polytope.h
constIteratorOfListOfGeometricObjects::next
void next()
Move the iterator one step forward.
Definition: GeometricObjectIterator_Rn.h:153
FaceEnumeration::load
static void load(const std::string &filename, std::vector< std::vector< ListOfFaces > > &latt)
Load the polytope lattice.
Definition: PolyhedralAlgorithms_Rn.cpp:261
FaceEnumeration::Compute
static void Compute(const boost::shared_ptr< Polytope_Rn > &A)
Definition: PolyhedralAlgorithms_Rn.cpp:43
IO_Polytope::save
static polito_EXPORT void save(const std::string &filename, boost::shared_ptr< PolyhedralCone_Rn > POLY)
Save the polytope to the main data format.
Definition: IO_Polytope.cpp:132
Rn::getTolerance
static polito_EXPORT double getTolerance()
Give the minimum distance between two points.
Definition: Rn.cpp:31
NormalFan_Rn.h
SortedNormedVector::operator()
bool operator()(std::pair< double, NormedHS > pt1, std::pair< double, NormedHS > pt2)
Definition: PolyhedralAlgorithms_Rn.cpp:1730
Polytope_Rn
Model a polytope using its two equivalent definitions : the convex hull and the half-space intersecti...
Definition: Polytope_Rn.h:36
PseudoIntersectionWithoutCaps::PseudoIntersectionWithoutCaps
PseudoIntersectionWithoutCaps(const boost::shared_ptr< Polytope_Rn > &A, const boost::shared_ptr< Polytope_Rn > &B, boost::shared_ptr< Polytope_Rn > &C, const std::set< unsigned int > &firstOperandCaps, const std::set< unsigned int > &secondOperandCaps, std::set< unsigned int > &newCaps, double bb_size=1000.)
Remove all cap half-spaces and then compute the intersection of two capped polytopes.
Definition: PolyhedralAlgorithms_Rn.cpp:1190
MinkowskiSum
Compute the Minkowski sum of two polytopes.
Definition: PolyhedralAlgorithms_Rn.h:138