politopix  4.1.0
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
VolumeOfPolytopes_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) 2014-2015 : Delos Vincent
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Lesser General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Lesser General Public License for more details.
13 //
14 // You should have received a copy of the GNU Lesser General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
16 //
19 // I2M (UMR CNRS 5295 / University of Bordeaux)
20 
21 #include <string>
22 #include <iostream>
23 #include <boost/math/special_functions/factorials.hpp>
24 #include "VolumeOfPolytopes_Rn.h"
25 
26 VolumeOfPolytopes_Rn::VolumeOfPolytopes_Rn(const boost::shared_ptr<Polytope_Rn> P) {
27  _volume = -1.;
28  _polytope = P;
30  _numberOfFacets = P->numberOfHalfSpaces();
31  _numberOfVertices = P->numberOfGenerators();
32 
33  // Fill the ordered list of vertices by facet, by example :
34  // Facet0 : vertex_i, vertex_j, vertex_k, ...
35  // Facet1 : vertex_l, vertex_m, ...
36  // ...
37  _verticesByFacets = std::vector< std::vector< unsigned int > >(_numberOfFacets);
38  {
40  {for (iteHS.begin(); iteHS.end()!=true; iteHS.next()) {
41  unsigned int facetNumber = iteHS.currentIteratorNumber();
43  for (iteGN.begin(); iteGN.end()!=true; iteGN.next()) {
44  unsigned int vertexNumber = iteGN.currentIteratorNumber();
45  {for (unsigned int j=0; j<iteGN.current()->numberOfFacets(); j++) {
46  if (iteGN.current()->getFacet(j) == iteHS.current())
47  _verticesByFacets[facetNumber].push_back(vertexNumber);
48  }}
49  }
50  }}
51  }
52 
53  // Fill the ordered list of facets by vertices
54  // Vertex0 : facet_u, facet_v, facet_w, ...
55  // Vertex1 : facet_x, facet_y, ...
56  // ...
57  _facetsByVertices = std::vector< std::vector< unsigned int > >(_numberOfVertices);
58  {
60  {for (iteGN.begin(); iteGN.end()!=true; iteGN.next()) {
61  unsigned int vertexNumber = iteGN.currentIteratorNumber();
62  {for (unsigned int j=0; j<iteGN.current()->numberOfFacets(); j++) {
63  unsigned int facetNumber = P->getHalfSpaceNumber( iteGN.current()->getFacet(j) );
64  _facetsByVertices[vertexNumber].push_back(facetNumber);
65  }}
66  }}
67  }
68 
69 #ifdef DEBUG
70  dumpDS(std::cout);
71 #endif
72 }
73 
74 void VolumeOfPolytopes_Rn::check() const throw (std::domain_error) {
75  //if (_listOfGN.size() == 0)
76  //throw std::domain_error("VolumeOfPolytopes_Rn::runComputations() empty list of generators !");
77  //if (_listOfHS.size() == 0)
78  //throw std::domain_error("VolumeOfPolytopes_Rn::runComputations() empty list of half-spaces !");
79 }
80 
82  // The algorithm main data structure to store the computations
83  std::stack< PolytopeToSimplexes > stackOfPolToSimp;
84  std::vector< unsigned int > listOfVtx;
85  // Build the first element to initialize the algorithm
86  for (unsigned int i=0; i<_polytope->numberOfGenerators(); ++i)
87  listOfVtx.push_back(i);
88  PolytopeToSimplexes P2S(listOfVtx, DIM);
89  stackOfPolToSimp.push(P2S);
90 
91  while (stackOfPolToSimp.size() != 0) {
92 #ifdef DEBUG
93  unsigned int shift = _dimension-stackOfPolToSimp.top().dimension();
94  std::cout << "The top of the stack is:" << std::endl;
95  stackOfPolToSimp.top().dump(std::cout, shift);
96 #endif
97  const PolytopeToSimplexes& topOfStack = stackOfPolToSimp.top();
98  if (topOfStack.checkSimplex() == true) {
99 #ifdef DEBUG
100  std::cout << "[*** The current polytope is a simplex ***]" << std::endl;
101 #endif
102  // Here we have two possibilities: full dimension or low dimension.
103  if (topOfStack.dimension() < _dimension) {
104  stackOfPolToSimp.top().switchToFullDimension();
105  }
106  // Now it's a fully dimensional simplex store it on the side and remove it from the stack.
107  _allSimplices.push_back(stackOfPolToSimp.top());
108 #ifdef DEBUG
109  std::cout << "After switchToFullDimension():" << std::endl;
110  stackOfPolToSimp.top().dump(std::cout, shift);
111 #endif
112  stackOfPolToSimp.pop();
113  }
114  else {
115  // 1. Split the current polytope into sub-polytopes
116  // 2. Insert the sub-polytopes into the list
117  // 3. Remove the father polytope
118 #ifdef DEBUG
119  std::cout << "[*** The current polytope is to be split ***]" << std::endl;
120 #endif
121  // Work on a copy
122  PolytopeToSimplexes topOfStack_cp = stackOfPolToSimp.top();
123  const std::vector< unsigned int >& vtx2plit = topOfStack_cp.getListOfVerticesToSplit();
124  unsigned int apexNumber = vtx2plit[0];
125  std::vector< unsigned int >::const_iterator itEnd = vtx2plit.end();
126  std::vector< unsigned int >::const_iterator itBeg = vtx2plit.begin();
127  ++itBeg;
128  // Insert all elements except the first one, this list should be ordered.
129  std::vector< unsigned int > newVtx;
130  newVtx.insert(newVtx.begin(), itBeg, itEnd);
131 
132  // Now remove the old polytope that has been split.
133  stackOfPolToSimp.pop();
134 
135  {for (unsigned int facetNumber=0; facetNumber<_numberOfFacets; ++facetNumber) {
136  // Exclude all facets belonging to the apex.
137 #ifdef DEBUG
138  std::cout << "Search " << facetNumber << " in : ";
139  std::copy(_facetsByVertices[apexNumber].begin(), _facetsByVertices[apexNumber].end(), std::ostream_iterator<unsigned int>(std::cout, " "));
140  std::cout << std::endl;
141 #endif
142  if (std::binary_search(_facetsByVertices[apexNumber].begin(), _facetsByVertices[apexNumber].end(), facetNumber) == false) {
143  // This is not a facet of the apex so split the base now.
144 #ifdef DEBUG
145  for (unsigned int i=0; i<_dimension-topOfStack_cp.dimension(); ++i) std::cout << "\t";
146  std::cout << "Not found facet number : " << facetNumber << std::endl;
147 #endif
148  // Split the cloud of points in baseToSimplices according to their facets.
149  // verticesOnGivenFacet = vertices of baseToSimplices which are on the facetNumber-th half-space.
150  std::vector< unsigned int > verticesOnGivenFacet;
151  std::set_intersection(
152  newVtx.begin(),
153  newVtx.end(),
154  _verticesByFacets[facetNumber].begin(),
155  _verticesByFacets[facetNumber].end(),
156  std::inserter( verticesOnGivenFacet, verticesOnGivenFacet.begin() ) );
157  if (verticesOnGivenFacet.size() >= topOfStack_cp.dimension()) {
158  PolytopeToSimplexes newP2S(verticesOnGivenFacet, topOfStack_cp.getListOfProcessedVertices(), apexNumber, topOfStack_cp.dimension()-1);
159  stackOfPolToSimp.push(newP2S);
160 #ifdef DEBUG
161  std::cout << "{ ";
162  std::copy(newVtx.begin(), newVtx.end(), std::ostream_iterator<unsigned int>(std::cout, " "));
163  std::cout << "} INTER { ";
164  std::copy(_verticesByFacets[facetNumber].begin(), _verticesByFacets[facetNumber].end(), std::ostream_iterator<unsigned int>(std::cout, " "));
165  std::cout << "}" << std::endl;
166  for (unsigned int i=0; i<_dimension-newP2S.dimension(); ++i) std::cout << "\t";
167  std::cout << "{" << newP2S.dimension() << ":";
168  std::copy(newP2S.getListOfProcessedVertices().begin(), newP2S.getListOfProcessedVertices().end(), std::ostream_iterator<unsigned int>(std::cout, " "));
169  std::cout << std::endl;
170  for (unsigned int i=0; i<_dimension-newP2S.dimension(); ++i) std::cout << "\t";
171  std::copy(newP2S.getListOfVerticesToSplit().begin(), newP2S.getListOfVerticesToSplit().end(), std::ostream_iterator<unsigned int>(std::cout, " "));
172  std::cout << "}" << std::endl;
173 #endif
174  }
175  }
176  }}
177  }
178  }
179 
180 
181 #ifdef DEBUG
182  std::cout << "_allSimplices : " << std::endl;
183  for (std::vector< PolytopeToSimplexes >::iterator it=_allSimplices.begin(); it!=_allSimplices.end(); ++it) {
184  std::cout << "{" << it->dimension() << ":";
185  std::copy(it->getListOfProcessedVertices().begin(), it->getListOfProcessedVertices().end(), std::ostream_iterator<unsigned int>(std::cout, " "));
186  std::cout << std::endl;
187  std::copy(it->getListOfVerticesToSplit().begin(), it->getListOfVerticesToSplit().end(), std::ostream_iterator<unsigned int>(std::cout, " "));
188  std::cout << "}" << std::endl;
189  std::cout << std::endl;
190  }
191 #endif
192 }
193 
195  _volume = 0.;
196 #ifdef DEBUG
197  std::cout << "VolumeOfPolytopes_Rn::volume() : " << _allSimplices.size() << std::endl;
198 #endif
199  std::set< std::set< boost::shared_ptr<Generator_Rn> > > listOfCoordSimplices;
200  std::vector< PolytopeToSimplexes >::iterator it1;
201  {for (it1=_allSimplices.begin(); it1!=_allSimplices.end(); ++it1) {
202  if (it1->dimension() == _dimension) {
203  std::set< boost::shared_ptr<Generator_Rn> > setOfGN;
204  std::vector< unsigned int >::const_iterator it2;
205 #ifdef DEBUG
206  std::cout << "Current simplex : ";
207  std::copy(it1->getListOfProcessedVertices().begin(), it1->getListOfProcessedVertices().end(), std::ostream_iterator<unsigned int>(std::cout, " "));
208  std::cout << std::endl;
209 #endif
210  {for (it2=it1->getListOfProcessedVertices().begin(); it2!=it1->getListOfProcessedVertices().end(); ++it2) {
211  setOfGN.insert(_polytope->getGenerator( *it2 ));
212  }}
213  listOfCoordSimplices. insert(setOfGN);
214  }
215  }}
216 
217  std::set< std::set< boost::shared_ptr<Generator_Rn> > >::const_iterator constITER_setGN;
218  {for (constITER_setGN=listOfCoordSimplices.begin(); constITER_setGN!=listOfCoordSimplices.end(); ++constITER_setGN) {
219  double current_volume = fabs( computeSimplexVolume(*constITER_setGN) );
220 #ifdef DEBUG
221  std::cout << "volumeOfSimplex=" << current_volume << std::endl;
222 #endif
223  _volume += current_volume;
224  }}
225  return _volume / (double) boost::math::factorial<double>(_dimension);
226 }
227 
228 double VolumeOfPolytopes_Rn::computeSimplexVolume(const std::set< boost::shared_ptr<Generator_Rn> >& listOfSimplexVertices) const
229 {
230  unsigned int RnDIM=Rn::getDimension();
231  boost::shared_ptr<Generator_Rn> vx0 = *(listOfSimplexVertices.begin());
232  boost::numeric::ublas::matrix<double> mat2computeDET(RnDIM, RnDIM);
233  std::set< boost::shared_ptr<Generator_Rn> >::const_iterator constITER_GN = listOfSimplexVertices.begin();
234  constITER_GN++;
235  unsigned int i=0;
236  {for ( ; constITER_GN!=listOfSimplexVertices.end(); ++constITER_GN) {
237  for (unsigned int j=0; j<mat2computeDET.size2(); ++j)
238  mat2computeDET(i,j) = (*constITER_GN)->getCoordinate(j) - vx0->getCoordinate(j);
239  i++;
240  }}
241 #ifdef DEBUG
242  std::cout << "mat2computeDET=" << mat2computeDET << std::endl;
243 #endif
244  return determinant(mat2computeDET);
245 }
246 
247 double VolumeOfPolytopes_Rn::determinant(boost::numeric::ublas::matrix<double> mat) const
248 {
249  double det = 0;
250  unsigned int i,j,j1,j2;
251  unsigned int n = mat.size1();
252 
253  if (n < 1) { // Error
254  }
255  else if (n == 1) { // Shouldn't get used
256  det = mat(0,0);
257  }
258  else if (n == 2) {
259  det = mat(0,0)*mat(1,1) - mat(1,0)*mat(0,1);
260  }
261  else {
262  det = 0;
263  for (j1=0; j1<n; j1++) {
264  boost::numeric::ublas::matrix<double> smaller_mat(n-1, n-1);
265  for (i=1; i<n; i++) {
266  j2 = 0;
267  for (j=0; j<n; j++) {
268  if (j == j1)
269  continue;
270  smaller_mat(i-1,j2) = mat(i,j);
271  j2++;
272  }
273  }
274  det += pow(-1.0, 1.0+j1+1.0) * mat(0,j1) * VolumeOfPolytopes_Rn::determinant(smaller_mat);
275  }
276  }
277  return(det);
278 }
unsigned int dimension() const
std::vector< PolytopeToSimplexes > _allSimplices
List to store all the simplices partitioning the polytope.
unsigned int _numberOfFacets
The number of facets of the current polytope.
double computeSimplexVolume(const std::set< boost::shared_ptr< Generator_Rn > > &listOfSimplexVertices) const
std::vector< std::vector< unsigned int > > _verticesByFacets
The ordered list of all vertices stored by facets.
const std::vector< unsigned int > & getListOfVerticesToSplit() const
int currentIteratorNumber() const
Return the current position in the list.
void dumpDS(std::ostream &this_ostream) const
boost::shared_ptr< Polytope_Rn > _polytope
The current polytope we are working on.
unsigned int _numberOfVertices
The number of vertices of the current polytope.
static polito_EXPORT unsigned int getDimension()
Return the dimension of the cartesian space we work in.
Definition: Rn.cpp:29
double _volume
The volume of the polytope.
std::vector< std::vector< unsigned int > > _facetsByVertices
The ordered list of all facets stored by vertices.
const std::vector< unsigned int > & getListOfProcessedVertices() const
double volume()
Sum the volumes of all simplices partitionning the polytope.
unsigned int _dimension
As the algorithm goes down in lower dimensions, we want to store the starting space dimension...
This class is designed to run the list of all geometric objects representing a polytope.
void splitCloudOfVertices(unsigned int DIM)
double determinant(boost::numeric::ublas::matrix< double > a) const
VolumeOfPolytopes_Rn(const boost::shared_ptr< Polytope_Rn > P)
Constructor.