1212from scipy .spatial import Delaunay
1313from scipy .special import comb
1414from copy import copy
15- import cdd
15+ import cdd as cdd_float
1616
1717from .material import cached_property
1818
1919from ..utils .math import independent_row_indices
2020
21- cdd_number_type = "float"
21+ cdd_gmp_loaded = False
22+
23+ try :
24+ cdd_fraction = importlib .import_module ("cdd.gmp" )
25+ cdd_gmp_loaded = True
26+ except ImportError as err :
27+ cdd_fraction = importlib .import_module ("cdd" )
28+ print (
29+ f"Warning: { err } . Only pycddlib-standalone is installed."
30+ "For precise fractional representations of polytopes, please install pycddlib."
31+ )
2232
2333
2434class SimplexGrid (object ):
@@ -117,7 +127,6 @@ def __init__(
117127 self ,
118128 equalities ,
119129 inequalities ,
120- number_type = "fraction" ,
121130 return_fractions = False ,
122131 independent_endmember_occupancies = None ,
123132 ):
@@ -133,25 +142,38 @@ def __init__(
133142 :type inequalities: numpy.array (2D)
134143 :param number_type: Whether pycddlib should read the input arrays as
135144 fractions or floats. Valid options are 'fraction' or 'float'.
136- :type number_type: str
137- :param return_fractions: Choose whether the generated polytope object
138- should return fractions or floats.
139145 :type return_fractions: bool
140146 :param independent_endmember_occupancies: If specified, this array
141147 provides the independent endmember set against which the
142148 dependent endmembers are defined.
143149 :type independent_endmember_occupancies: numpy.array (2D) or None
144150 """
151+ if equalities .dtype != inequalities .dtype :
152+ raise Exception (
153+ f"The dtype of the equalities ({ equalities .dtype } ) and inequalities ({ inequalities .dtype } ) arrays should be the same."
154+ )
155+
145156 self .set_return_type (return_fractions )
146157 self .equality_matrix = equalities [:, 1 :]
147158 self .equality_vector = - equalities [:, 0 ]
148159
149- self .polytope_matrix = cdd .matrix_from_array (equalities )
160+ if equalities .dtype == Fraction and cdd_gmp_loaded is True :
161+ self .number_type = Fraction
162+ self .cdd = cdd_fraction
163+ elif equalities .dtype == float or cdd_gmp_loaded is False :
164+ self .number_type = float
165+ self .cdd = cdd_float
166+ else :
167+ raise Exception ("number_type should be either float or Fraction." )
168+
169+ self .polytope_matrix = self .cdd .matrix_from_array (equalities )
150170 self .polytope_matrix .lin_set = set (range (len (equalities )))
151- self .polytope_matrix .rep_type = cdd .RepType .INEQUALITY
171+ self .polytope_matrix .rep_type = self . cdd .RepType .INEQUALITY
152172
153- cdd .matrix_append_to (self .polytope_matrix , cdd .matrix_from_array (inequalities ))
154- self .polytope = cdd .polyhedron_from_matrix (self .polytope_matrix )
173+ self .cdd .matrix_append_to (
174+ self .polytope_matrix , self .cdd .matrix_from_array (inequalities )
175+ )
176+ self .polytope = self .cdd .polyhedron_from_matrix (self .polytope_matrix )
155177
156178 if independent_endmember_occupancies is not None :
157179 self .independent_endmember_occupancies = independent_endmember_occupancies
@@ -177,14 +199,14 @@ def raw_vertices(self):
177199 Returns a list of the vertices of the polytope without any
178200 postprocessing. See also endmember_occupancies.
179201 """
180- return cdd .copy_generators (self .polytope ).array
202+ return self . cdd .copy_generators (self .polytope ).array
181203
182204 @cached_property
183205 def limits (self ):
184206 """
185207 Return the limits of the polytope (the set of bounding inequalities).
186208 """
187- return np .array (cdd .copy_inequalities (self .polytope ).array , dtype = float )
209+ return np .array (self . cdd .copy_inequalities (self .polytope ).array , dtype = float )
188210
189211 @cached_property
190212 def n_endmembers (self ):
@@ -200,20 +222,15 @@ def endmember_occupancies(self):
200222 Return the endmember occupancies
201223 (a processed list of all of the vertex locations).
202224 """
203- if self .return_fractions :
204- if cdd_number_type == "fraction" :
205- v = np .array (
206- [[Fraction (value ) for value in v ] for v in self .raw_vertices ]
207- )
208- else :
209- v = np .array (
210- [
211- [Rational (value ).limit_denominator (1000000 ) for value in v ]
212- for v in self .raw_vertices
213- ]
214- )
225+ if self .number_type == float and self .return_fractions :
226+ v = np .array (
227+ [
228+ [Rational (value ).limit_denominator (1000000 ) for value in v ]
229+ for v in self .raw_vertices
230+ ]
231+ )
215232 else :
216- v = np .array ([[ float ( value ) for value in v ] for v in self .raw_vertices ] )
233+ v = np .array (self .raw_vertices )
217234
218235 if len (v .shape ) == 1 :
219236 raise ValueError (
@@ -275,9 +292,10 @@ def independent_endmember_polytope(self):
275292 """
276293 arr = self .endmembers_as_independent_endmember_amounts
277294 arr = np .hstack ((np .ones ((len (arr ), 1 )), arr [:, :- 1 ]))
278- M = cdd .matrix_from_array (arr )
279- M .rep_type = cdd .RepType .GENERATOR
280- return cdd .polyhedron_from_matrix (M )
295+ arr = [[Fraction (value ).limit_denominator (1000000 ) for value in v ] for v in arr ]
296+ M = cdd_fraction .matrix_from_array (arr )
297+ M .rep_type = cdd_fraction .RepType .GENERATOR
298+ return cdd_fraction .polyhedron_from_matrix (M )
281299
282300 @cached_property
283301 def independent_endmember_limits (self ):
@@ -286,7 +304,7 @@ def independent_endmember_limits(self):
286304 endmembers.
287305 """
288306 ind_poly = self .independent_endmember_polytope
289- inequalities = cdd .copy_inequalities (ind_poly ).array
307+ inequalities = cdd_fraction .copy_inequalities (ind_poly ).array
290308 return np .array (inequalities , dtype = float )
291309
292310 def subpolytope_from_independent_endmember_limits (self , limits ):
@@ -295,18 +313,20 @@ def subpolytope_from_independent_endmember_limits(self, limits):
295313 of the independent endmembers.
296314 """
297315 ind_poly = self .independent_endmember_polytope
298- modified_limits = cdd .copy_inequalities (ind_poly )
299- cdd .matrix_append_to (modified_limits , cdd .matrix_from_array (limits ))
300- return cdd .polyhedron_from_matrix (modified_limits )
316+ modified_limits = cdd_fraction .copy_inequalities (ind_poly )
317+ cdd_fraction .matrix_append_to (
318+ modified_limits , cdd_fraction .matrix_from_array (limits )
319+ )
320+ return cdd_fraction .polyhedron_from_matrix (modified_limits )
301321
302322 def subpolytope_from_site_occupancy_limits (self , limits ):
303323 """
304324 Returns a smaller polytope by applying additional limits to the
305325 individual site occupancies.
306326 """
307327 modified_limits = copy (self .polytope_matrix )
308- cdd .matrix_append_to (modified_limits , cdd .matrix_from_array (limits ))
309- return cdd .polyhedron_from_matrix (modified_limits )
328+ self . cdd .matrix_append_to (modified_limits , self . cdd .matrix_from_array (limits ))
329+ return self . cdd .polyhedron_from_matrix (modified_limits )
310330
311331 def grid (
312332 self ,
@@ -358,7 +378,7 @@ def grid(
358378 else :
359379 if grid_type == "independent endmember proportions" :
360380 plims = self .subpolytope_from_site_occupancy_limits (limits )
361- ppns = np .array (cdd .copy_generators (plims ).array )[:, 1 :]
381+ ppns = np .array (self . cdd .copy_generators (plims ).array )[:, 1 :]
362382 last_ppn = np .array ([1.0 - sum (p ) for p in ppns ]).reshape (
363383 (len (ppns ), 1 )
364384 )
@@ -371,7 +391,7 @@ def grid(
371391
372392 elif grid_type == "site occupancies" :
373393 plims = self .subpolytope_from_site_occupancy_limits (limits )
374- occ = np .array (cdd .copy_generators (plims ).array )[:, 1 :]
394+ occ = np .array (self . cdd .copy_generators (plims ).array )[:, 1 :]
375395 f_occ = occ / (points_per_edge - 1 )
376396
377397 ind = self .independent_endmember_occupancies
0 commit comments