The ChainCon Software (Release 0.03)
simplex.h
Go to the documentation of this file.
1 /////////////////////////////////////////////////////////////////////////////
2 ///
3 /// \file
4 ///
5 /// A simplex class with arbitrary vertices.
6 ///
7 /////////////////////////////////////////////////////////////////////////////
8 
9 // Copyright (C) 2009-2016 by Pawel Pilarczyk.
10 //
11 // This file is part of my research software package. This is free software:
12 // you can redistribute it and/or modify it under the terms of the GNU
13 // General Public License as published by the Free Software Foundation,
14 // either version 3 of the License, or (at your option) any later version.
15 //
16 // This software is distributed in the hope that it will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 // GNU General Public License for more details.
20 //
21 // You should have received a copy of the GNU General Public License
22 // along with this software; see the file "license.txt". If not,
23 // please, see <http://www.gnu.org/licenses/>.
24 
25 // Started on March 24, 2009. Last revision: August 4, 2015.
26 
27 
28 #ifndef _CHAINCON_SIMPLEX_H_
29 #define _CHAINCON_SIMPLEX_H_
30 
31 
32 // include some standard C++ header files
33 #include <istream>
34 #include <ostream>
35 #include <algorithm>
36 #include <vector>
37 
38 // include selected header files from the CHomP library
39 #include "chomp/system/config.h"
40 
41 // include relevant local header files
42 #include "chaincon/emptycell.h"
43 
44 
45 // --------------------------------------------------
46 // --------------------- simplex --------------------
47 // --------------------------------------------------
48 
49 /// A simplex with vertices of arbitrary type.
50 /// Note that the vertex type must have hash key functions
51 /// (defined in chomp/struct/hashsets.h for most built-in integers,
52 /// defined in chaincon/stringhash.h for std::string, or your own).
53 /// The empty cell existence decision class must provide a static function
54 /// "exists" that returns true if the empty cell must be taken
55 /// into consideration or false otherwise.
56 /// Important: The vertices are assumed to be given in the ascending order;
57 /// otherwise the operator == may give false negatives!
58 template <class VertexT, class EmptyT>
59 class tSimplex
60 {
61 public:
62  /// The type of the vertex.
63  typedef VertexT VertexType;
64 
65  /// The type of the empty cell existence decision class.
66  typedef EmptyT EmptyType;
67 
68  /// The default constructor of an empty simplex.
69  tSimplex ();
70 
71  /// The constructor of a simplex from an array of vertices.
72  template <class VertexArray>
73  tSimplex (int dimension, const VertexArray &vertices);
74 
75  /// The copy constructor.
77 
78  /// The constructor of the n-th face of a simplex (if n >= 0)
79  /// or the k-th degeneracy operator (if n = -1 - k < 0).
80  tSimplex (const tSimplex<VertexT,EmptyT> &s, int n);
81 
82  /// The assignment operator.
83  tSimplex<VertexT,EmptyT> &operator =
84  (const tSimplex<VertexT,EmptyT> &s);
85 
86  /// The destructor.
87  ~tSimplex ();
88 
89  /// Returns the dimension of the simplex.
90  int dim () const;
91 
92  /// Returns the n-th vertex of the simplex.
93  const VertexT &operator [] (int n) const;
94 
95  /// Returns the length of the boundary of the simplex.
96  int boundaryLength () const;
97 
98  /// Returns the n-th coefficient in the boundary of the simplex.
99  int boundaryCoef (int n) const;
100 
101  /// Checks if the simplex is degenerate, that is, if it has two
102  /// identical vertices one after another. If this is the case
103  /// then returns the position of the second vertex.
104  /// Returns 0 if the simplex is not degenerate.
105  int degenerate () const;
106 
107  /// The equality operator.
108  /// Verifies if the vertices are the same and in the same order.
109  /// Note that this may result in false negatives if the vertices
110  /// are stored in various orders.
111  bool operator == (const tSimplex<VertexT,EmptyT> &s) const;
112 
113  /// Swaps the data between two simplices.
114  void swap (tSimplex<VertexT,EmptyT> &s);
115 
116 private:
117  /// The dimension of the simplex.
119 
120  /// An array of vertices of the simplex.
121  VertexT *vertices;
122 }; /* class tSimplex */
123 
124 // --------------------------------------------------
125 
126 template <class VertexT, class EmptyT>
128  dimension (-1), vertices (0)
129 {
130  return;
131 } /* tSimplex::tSimplex */
132 
133 template <class VertexT, class EmptyT>
134 template <class VertexArray>
136  const VertexArray &vertices)
137 {
138  // make sure that the vertices are in the ascending order
139  for (int i = 0; i < dimension; ++ i)
140  {
141  if (vertices [i + 1] < vertices [i])
142  throw "Wrong order of vertices of a simplex.";
143  }
144 
145  // allocate memory for the simplex and store its dimension
146  this -> dimension = (dimension >= 0) ? dimension : -1;
147  this -> vertices = (dimension >= 0) ? new VertexT [dimension + 1] : 0;
148 
149  // copy the values of the vertices to the inernal array
150  for (int i = 0; i <= dimension; ++ i)
151  this -> vertices [i] = vertices [i];
152  return;
153 } /* tSimplex::tSimplex */
154 
155 template <class VertexT, class EmptyT>
157 {
158  dimension = s. dimension;
159  vertices = (dimension >= 0) ? new VertexT [dimension + 1] : 0;
160  for (int i = 0; i <= dimension; ++ i)
161  vertices [i] = s. vertices [i];
162  return;
163 } /* tSimplex::tSimplex */
164 
165 template <class VertexT, class EmptyT>
167  int n)
168 {
169  if (n >= 0)
170  {
171  dimension = (s. dimension >= 0) ? (s. dimension - 1) : -1;
172  vertices = (dimension >= 0) ? new VertexT [dimension + 1] : 0;
173  for (int i = 0; i < n; ++ i)
174  vertices [i] = s. vertices [i];
175  for (int i = n; i <= dimension; ++ i)
176  vertices [i] = s. vertices [i + 1];
177  }
178  else
179  {
180  dimension = (s. dimension >= 0) ? (s. dimension + 1) : -1;
181  vertices = (dimension >= 0) ? new VertexT [dimension + 1] : 0;
182  for (int i = 0; i < -n; ++ i)
183  vertices [i] = s. vertices [i];
184  for (int i = -n; i <= dimension; ++ i)
185  vertices [i] = s. vertices [i - 1];
186  }
187  return;
188 } /* tSimplex::tSimplex */
189 
190 template <class VertexT, class EmptyT>
193 {
194  if (dimension != s. dimension)
195  {
196  if (vertices)
197  delete [] vertices;
198  dimension = s. dimension;
199  vertices = (dimension >= 0) ?
200  new VertexT [dimension + 1] : 0;
201  }
202  for (int i = 0; i <= dimension; ++ i)
203  this -> vertices [i] = s. vertices [i];
204  return *this;
205 } /* tSimplex::operator = */
206 
207 template <class VertexT, class EmptyT>
209 {
210  if (vertices)
211  delete [] vertices;
212  return;
213 } /* tSimplex::~tSimplex */
214 
215 template <class VertexT, class EmptyT>
216 inline int tSimplex<VertexT,EmptyT>::dim () const
217 {
218  return dimension;
219 } /* tSimplex::dim */
220 
221 template <class VertexT, class EmptyT>
222 inline const VertexT &tSimplex<VertexT,EmptyT>::operator [] (int n) const
223 {
224  return vertices [n];
225 } /* tSimplex::operator [] */
226 
227 template <class VertexT, class EmptyT>
229 {
230  if (EmptyT::exists ())
231  return dimension + 1;
232  else
233  return (dimension > 0) ? (dimension + 1) : 0;
234 } /* tSimplex::boundaryLength */
235 
236 template <class VertexT, class EmptyT>
238 {
239  return (n & 1) ? -1 : 1;
240 } /* tSimplex::boundaryCoef */
241 
242 template <class VertexT, class EmptyT>
244 {
245  for (int i = 1; i <= dimension; ++ i)
246  {
247  if (vertices [i - 1] == vertices [i])
248  return i;
249  }
250  return 0;
251 } /* tSimplex::degenerate */
252 
253 template <class VertexT, class EmptyT>
254 inline bool tSimplex<VertexT,EmptyT>::operator ==
255  (const tSimplex<VertexT,EmptyT> &s) const
256 {
257  if (dimension != s. dimension)
258  return false;
259  for (int i = 0; i <= dimension; ++ i)
260  {
261  if (!(vertices [i] == s. vertices [i]))
262  return false;
263  }
264  return true;
265 } /* tSimplex::operator == */
266 
267 template <class VertexT, class EmptyT>
269 {
270  std::swap (dimension, s. dimension);
271  std::swap (vertices, s. vertices);
272  return;
273 } /* tSimplex::swap */
274 
275 // --------------------------------------------------
276 
277 /// Generates a hashing key no. 1 for a simplex,
278 /// composed of hashing keys for the vertices.
279 /// This key is to be used in a hashed set.
280 template <class VertexT, class EmptyT>
281 inline int_t hashkey1 (const tSimplex<VertexT,EmptyT> &s)
282 {
283 // using chomp::homology::hashkey1;
285  int d = s. dim ();
286  if (d < 0)
287  return 0;
288  else if (d == 0)
289  return hashkey1 (s [0]) << 2;
290  else if (d == 1)
291  {
292  return ((hashkey1 (s [0]) & 0x655555u) << 11) ^
293  ((hashkey1 (s [1]) & 0xAA00AAu) >> 1);
294  }
295  else
296  {
297  return ((hashkey1 (s [0]) & 0x655555u) << 15) ^
298  ((hashkey1 (s [d >> 1]) & 0xAA00AAu) << 1) ^
299  ((hashkey1 (s [d]) & 0xAAAAAAu) >> 7);
300  }
301 } /* hashkey1 */
302 
303 /// Generates a hashing key no. 2 for a simplex,
304 /// composed of hashing keys for the vertices.
305 /// This key is to be used in a hashed set.
306 template <class VertexT, class EmptyT>
307 inline int_t hashkey2 (const tSimplex<VertexT,EmptyT> &s)
308 {
309 // using chomp::homology::hashkey2;
311  int d = s. dim ();
312  if (d < 0)
313  return 0;
314  else if (d == 0)
315  return hashkey2 (s [0]) << 4;
316  else if (d == 1)
317  {
318  return ((hashkey2 (s [0]) & 0xAAAAAAu) >> 2) ^
319  ((hashkey2 (s [1]) & 0x555555u) << 8);
320  }
321  else
322  {
323  return ((hashkey2 (s [d]) & 0x555555u) << 7) ^
324  ((hashkey2 (s [0]) & 0xAA00AAu) << 5) ^
325  ((hashkey2 (s [d >> 1]) & 0xAAAAu) >> 5);
326  }
327 } /* hashkey2 */
328 
329 // --------------------------------------------------
330 
331 /// Writes a simplex in the text mode to an output stream.
332 /// All the vertices are written using their operator <<,
333 /// and are enclosed in parentheses in a comma-separated list.
334 template <class VertexT, class EmptyT>
335 std::ostream &operator << (std::ostream &out, const tSimplex<VertexT,EmptyT> &s)
336 {
337  int dim = s. dim ();
338  out << "(";
339  for (int i = 0; i <= dim; ++ i)
340  {
341  if (i)
342  out << ',';
343  out << s [i];
344  }
345  out << ")";
346  return out;
347 } /* operator << */
348 
349 /// Reads a simplex from the input stream in the text format.
350 /// Skips all the characters in the input stream until
351 /// an opening parenthesis is found. Then reads the vertices
352 /// of the simplex using their operator >> as a comma-separated list.
353 /// The closing parenthesis indicates the end of the simplex definition.
354 /// If the closing parenthesis is not found then an exception is thrown.
355 /// If no simplex is found in the input then the simplex is not modified.
356 template <class VertexT, class EmptyT>
357 std::istream &operator >> (std::istream &in, tSimplex<VertexT,EmptyT> &s)
358 {
359  // ignore any comments, spaces, tabs and new-line characters
360  chomp::homology::ignorecomments (in);
361 
362  // read the opening parenthesis
363  int ch = in. get ();
364  if (ch != '(')
365  return in;
366 
367  // read a comma-separated list of vertices of the simplex
368  std::vector<VertexT> vertices;
369  ch = in. peek ();
370  while ((ch != EOF) && (ch != ')'))
371  {
372  VertexT vertex;
373  in >> vertex;
374  vertices. push_back (vertex);
375  while ((in. peek () == ' ') || (in. peek () == ','))
376  ch = in. get ();
377  if (in. peek () == ')')
378  ch = in. get ();
379  }
380  if (ch != ')')
381  throw "Simplex reading error: ')' expected.\n";
382 
383  // make sure that the vertices are in the ascending order
384  for (unsigned i = 1; i < vertices. size (); ++ i)
385  {
386  if (vertices [i - 1] >= vertices [i])
387  throw "Simplex reading error: wrong vertices.\n";
388  }
389 
390  // define the simplex
391  s = tSimplex<VertexT,EmptyT> (vertices. size () - 1, vertices);
392 
393  return in;
394 } /* operator >> */
395 
396 
397 #endif // _CHAINCON_SIMPLEX_H_
398 
int boundaryCoef(int n) const
Returns the n-th coefficient in the boundary of the simplex.
Definition: simplex.h:237
EmptyT EmptyType
The type of the empty cell existence decision class.
Definition: simplex.h:66
A simplex with vertices of arbitrary type.
Definition: simplex.h:59
bool operator==(const tSimplex< VertexT, EmptyT > &s) const
The equality operator.
Definition: simplex.h:255
int dim() const
Returns the dimension of the simplex.
Definition: simplex.h:216
~tSimplex()
The destructor.
Definition: simplex.h:208
VertexT * vertices
An array of vertices of the simplex.
Definition: simplex.h:121
std::istream & operator>>(std::istream &in, tSimplex< VertexT, EmptyT > &s)
Reads a simplex from the input stream in the text format.
Definition: simplex.h:357
int degenerate() const
Checks if the simplex is degenerate, that is, if it has two identical vertices one after another...
Definition: simplex.h:243
int_t hashkey2(const tSimplex< VertexT, EmptyT > &s)
Generates a hashing key no.
Definition: simplex.h:307
The decision on whether the empty cell should be used as a valid cell of dimension -1...
int boundaryLength() const
Returns the length of the boundary of the simplex.
Definition: simplex.h:228
tSimplex()
The default constructor of an empty simplex.
Definition: simplex.h:127
int dimension
The dimension of the simplex.
Definition: simplex.h:118
int_t hashkey1(const tSimplex< VertexT, EmptyT > &s)
Generates a hashing key no.
Definition: simplex.h:281
VertexT VertexType
The type of the vertex.
Definition: simplex.h:63
void swap(tSimplex< VertexT, EmptyT > &s)
Swaps the data between two simplices.
Definition: simplex.h:268
const VertexT & operator[](int n) const
Returns the n-th vertex of the simplex.
Definition: simplex.h:222