Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/geometry/polyhedron/backend_cdd.py
4091 views
1
"""
2
The cdd backend for polyhedral computations
3
"""
4
5
from subprocess import Popen, PIPE
6
from sage.rings.all import ZZ, QQ, RDF
7
from sage.misc.all import SAGE_TMP, tmp_filename, union, cached_method, prod
8
from sage.matrix.constructor import matrix
9
10
from base import Polyhedron_base
11
from base_QQ import Polyhedron_QQ
12
from base_RDF import Polyhedron_RDF
13
from representation import (
14
PolyhedronRepresentation,
15
Hrepresentation,
16
Inequality, Equation,
17
Vrepresentation,
18
Vertex, Ray, Line )
19
20
21
22
#########################################################################
23
class Polyhedron_cdd(Polyhedron_base):
24
"""
25
Base class for the cdd backend.
26
"""
27
28
def _init_from_Vrepresentation(self, ambient_dim, vertices, rays, lines, verbose=False):
29
"""
30
Construct polyhedron from V-representation data.
31
32
INPUT:
33
34
- ``ambient_dim`` -- integer. The dimension of the ambient space.
35
36
- ``vertices`` -- list of point. Each point can be specified
37
as any iterable container of
38
:meth:`~sage.geometry.polyhedron.base.base_ring` elements.
39
40
- ``rays`` -- list of rays. Each ray can be specified as any
41
iterable container of
42
:meth:`~sage.geometry.polyhedron.base.base_ring` elements.
43
44
- ``lines`` -- list of lines. Each line can be specified as
45
any iterable container of
46
:meth:`~sage.geometry.polyhedron.base.base_ring` elements.
47
48
- ``verbose`` -- boolean (default: ``False``). Whether to print
49
verbose output for debugging purposes.
50
51
EXAMPLES::
52
53
sage: Polyhedron(vertices=[(0,0)], rays=[(1,1)],
54
... lines=[(1,-1)], backend='cddr') # indirect doctest
55
A 2-dimensional polyhedron in QQ^2 defined as the
56
convex hull of 1 vertex, 1 ray, 1 line
57
"""
58
from cdd_file_format import cdd_Vrepresentation
59
s = cdd_Vrepresentation(self._cdd_type, vertices, rays, lines)
60
self._init_from_cdd_input(s, '--reps', verbose)
61
62
63
def _init_from_Hrepresentation(self, ambient_dim, ieqs, eqns, verbose=False):
64
"""
65
Construct polyhedron from H-representation data.
66
67
INPUT:
68
69
- ``ambient_dim`` -- integer. The dimension of the ambient space.
70
71
- ``ieqs`` -- list of inequalities. Each line can be specified
72
as any iterable container of
73
:meth:`~sage.geometry.polyhedron.base.base_ring` elements.
74
75
- ``eqns`` -- list of equalities. Each line can be specified
76
as any iterable container of
77
:meth:`~sage.geometry.polyhedron.base.base_ring` elements.
78
79
- ``verbose`` -- boolean (default: ``False``). Whether to print
80
verbose output for debugging purposes.
81
82
EXAMPLES::
83
84
sage: Polyhedron(ieqs=[(0,1,1)], eqns=[(0,1,-1)],
85
... backend='cddr') # indirect doctest
86
A 1-dimensional polyhedron in QQ^2 defined as the
87
convex hull of 1 vertex and 1 ray
88
"""
89
from cdd_file_format import cdd_Hrepresentation
90
s = cdd_Hrepresentation(self._cdd_type, ieqs, eqns)
91
self._init_from_cdd_input(s, '--reps', verbose)
92
93
94
def _init_facet_adjacency_matrix(self, verbose=False):
95
"""
96
Compute the facet adjacency matrix in case it has not been
97
computed during initialization.
98
99
EXAMPLES::
100
101
sage: p = Polyhedron(vertices=[(0,0),(1,0),(0,1)], backend='cddr')
102
sage: '_H_adjacency_matrix' in p.__dict__
103
False
104
sage: p._init_facet_adjacency_matrix()
105
sage: p._H_adjacency_matrix
106
[0 1 1]
107
[1 0 1]
108
[1 1 0]
109
"""
110
self._init_from_cdd_input(self.cdd_Hrepresentation(),
111
'--adjacency', verbose)
112
113
114
def _init_vertex_adjacency_matrix(self, verbose=False):
115
"""
116
Compute the vertex adjacency matrix in case it has not been
117
computed during initialization.
118
119
EXAMPLES::
120
121
sage: p = Polyhedron(vertices=[(0,0),(1,0),(0,1)], backend='cddr')
122
sage: '_V_adjacency_matrix' in p.__dict__
123
False
124
sage: p._init_vertex_adjacency_matrix()
125
sage: p._V_adjacency_matrix
126
[0 1 1]
127
[1 0 1]
128
[1 1 0]
129
"""
130
self._init_from_cdd_input(self.cdd_Vrepresentation(),
131
'--adjacency', verbose)
132
133
134
def _init_from_cdd_input(self, cdd_input_string, cmdline_arg='--all', verbose=False):
135
"""
136
Internal method: run cdd on a cdd H- or V-representation
137
and initialize ourselves with the output.
138
139
TESTS::
140
141
sage: p = Polyhedron(vertices = [[0,0,0],[1,0,0],[0,1,0],[0,0,1]], backend='cddr')
142
sage: from sage.geometry.polyhedron.cdd_file_format import cdd_Vrepresentation
143
sage: s = cdd_Vrepresentation('rational', [[0,0,1],[0,1,0],[1,0,0]], [], [])
144
sage: p._init_from_cdd_input(s)
145
sage: p.dim()
146
2
147
"""
148
if verbose: print cdd_input_string
149
150
cdd_proc = Popen([self._cdd_executable, cmdline_arg],
151
stdin=PIPE, stdout=PIPE, stderr=PIPE)
152
ans, err = cdd_proc.communicate(input=cdd_input_string)
153
154
# FIXME: check err
155
if verbose:
156
print ans
157
self._init_from_cdd_output(ans)
158
159
160
def _init_from_cdd_output(self, cdd_output_string):
161
"""
162
Initialize ourselves with the output from cdd.
163
164
TESTS::
165
166
sage: from sage.geometry.polyhedron.cdd_file_format import cdd_Vrepresentation
167
sage: s = cdd_Vrepresentation('rational',[[0,0],[1,0],[0,1],[1,1]], [], [])
168
sage: from subprocess import Popen, PIPE
169
sage: cdd_proc = Popen(['cdd_both_reps_gmp', '--all'], stdin=PIPE, stdout=PIPE, stderr=PIPE)
170
sage: ans, err = cdd_proc.communicate(input=s)
171
sage: p = Polyhedron(vertices = [[0,0],[1,0],[0,1],[1,1]], backend='cddr')
172
sage: p._init_from_cdd_output(ans)
173
sage: p.vertices()
174
[[0, 0], [1, 0], [0, 1], [1, 1]]
175
"""
176
cddout=cdd_output_string.splitlines()
177
suppressed_vertex = False # whether cdd suppressed the vertex in output
178
179
# nested function
180
def expect_in_cddout(expected_string):
181
l = cddout.pop(0).strip()
182
if l!=expected_string:
183
raise ValueError, ('Error while parsing cdd output: expected "'
184
+expected_string+'" but got "'+l+'".\n' )
185
# nested function
186
def cdd_linearities():
187
l = cddout[0].split()
188
if l[0] != "linearity":
189
return []
190
cddout.pop(0)
191
assert len(l) == int(l[1])+2, "Not enough linearities given"
192
return [int(i)-1 for i in l[2:]] # make indices pythonic
193
194
# nested function
195
def cdd_convert(string, field=self.field()):
196
"""
197
Converts the cdd output string to a numerical value.
198
"""
199
return [field(x) for x in string.split()]
200
201
# nested function
202
def find_in_cddout(expected_string):
203
"""
204
Find the expected string in a list of strings, and
205
truncates ``cddout`` to start at that point. Returns
206
``False`` if search fails.
207
"""
208
for pos in range(0,len(cddout)):
209
l = cddout[pos].strip();
210
if l==expected_string:
211
# must not assign to cddout in nested function
212
for i in range(0,pos+1):
213
cddout.pop(0)
214
return True
215
return False
216
217
if find_in_cddout('V-representation'):
218
self._Vrepresentation = []
219
lines = cdd_linearities()
220
expect_in_cddout('begin')
221
l = cddout.pop(0).split()
222
assert self._ambient_dim == int(l[1])-1, "Different ambient dimension?"
223
suppressed_vertex = True
224
for i in range(int(l[0])):
225
l = cddout.pop(0).strip()
226
l_type = l[0]
227
l = l[1:]
228
if i in lines:
229
Line(self, cdd_convert(l));
230
elif l_type == '0':
231
Ray(self, cdd_convert(l));
232
else:
233
Vertex(self, cdd_convert(l));
234
suppressed_vertex = False
235
if suppressed_vertex and self.n_Vrepresentation()>0:
236
# cdd does not output the vertex if it is only the origin
237
Vertex(self, [0] * self._ambient_dim)
238
self._Vrepresentation = tuple(self._Vrepresentation)
239
expect_in_cddout('end')
240
241
if find_in_cddout('H-representation'):
242
self._Hrepresentation = []
243
equations = cdd_linearities()
244
expect_in_cddout('begin')
245
l = cddout.pop(0).split()
246
assert self._ambient_dim == int(l[1])-1, "Different ambient dimension?"
247
for i in range(int(l[0])):
248
l = cddout.pop(0)
249
if i in equations:
250
Equation(self, cdd_convert(l));
251
else:
252
Inequality(self, cdd_convert(l));
253
self._Hrepresentation = tuple(self._Hrepresentation)
254
expect_in_cddout('end')
255
256
# nested function
257
def cdd_adjacencies():
258
l = cddout.pop(0).split()
259
assert l[2] == ':', "Not a line of the adjacency data?"
260
return [int(i)-1 for i in l[3:]]
261
262
if find_in_cddout('Vertex graph'):
263
n = len(self._Vrepresentation);
264
if suppressed_vertex:
265
n_cdd=n-1;
266
else:
267
n_cdd=n;
268
self._V_adjacency_matrix = matrix(ZZ, n, n, 0)
269
expect_in_cddout('begin')
270
l = cddout.pop(0).split()
271
assert int(l[0]) == n_cdd, "Not enough V-adjacencies in cdd output?"
272
for i in range(n_cdd):
273
for a in cdd_adjacencies():
274
self._V_adjacency_matrix[i,a] = 1
275
# cdd reports that lines are never adjacent to anything.
276
# I disagree, they are adjacent to everything!
277
if self._Vrepresentation[i].is_line():
278
for j in range(n):
279
self._V_adjacency_matrix[i,j] = 1
280
self._V_adjacency_matrix[j,i] = 1
281
self._V_adjacency_matrix[i,i] = 0
282
if suppressed_vertex: # cdd implied that there is only one vertex
283
for i in range(n-1):
284
self._V_adjacency_matrix[i,n-1] = 1
285
self._V_adjacency_matrix[n-1,i] = 1
286
self._V_adjacency_matrix.set_immutable()
287
expect_in_cddout('end')
288
289
if find_in_cddout('Facet graph'):
290
n = len(self._Hrepresentation);
291
self._H_adjacency_matrix = matrix(ZZ, n, n, 0)
292
expect_in_cddout('begin')
293
l = cddout.pop(0).split()
294
assert int(l[0]) == n, "Not enough H-adjacencies in cdd output?"
295
for i in range(n):
296
for a in cdd_adjacencies():
297
self._H_adjacency_matrix[i,a] = 1
298
self._H_adjacency_matrix.set_immutable()
299
expect_in_cddout('end')
300
301
302
#########################################################################
303
class Polyhedron_QQ_cdd(Polyhedron_cdd, Polyhedron_QQ):
304
"""
305
Polyhedra over QQ with cdd
306
307
INPUT:
308
309
- ``ambient_dim`` -- integer. The dimension of the ambient space.
310
311
- ``Vrep`` -- a list ``[vertices, rays, lines]``.
312
313
- ``Hrep`` -- a list ``[ieqs, eqns]``.
314
315
EXAMPLES::
316
317
sage: from sage.geometry.polyhedron.backend_cdd import Polyhedron_QQ_cdd
318
sage: Polyhedron_QQ_cdd(2, [ [(1,0),(0,1),(0,0)], [], []], None, verbose=False)
319
A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 3 vertices
320
"""
321
322
_cdd_type = 'rational'
323
324
_cdd_executable = 'cdd_both_reps_gmp'
325
326
def __init__(self, ambient_dim, Vrep, Hrep, **kwds):
327
"""
328
The Python constructor.
329
330
See :class:`Polyhedron_base` for a description of the input
331
data.
332
333
TESTS::
334
335
sage: p = Polyhedron(backend='cddr')
336
sage: type(p)
337
<class 'sage.geometry.polyhedron.backend_cdd.Polyhedron_QQ_cdd'>
338
sage: TestSuite(p).run()
339
"""
340
Polyhedron_cdd.__init__(self, ambient_dim, Vrep, Hrep, **kwds)
341
342
343
#########################################################################
344
class Polyhedron_RDF_cdd(Polyhedron_cdd, Polyhedron_RDF):
345
"""
346
Polyhedra over RDF with cdd
347
348
INPUT:
349
350
- ``ambient_dim`` -- integer. The dimension of the ambient space.
351
352
- ``Vrep`` -- a list ``[vertices, rays, lines]``.
353
354
- ``Hrep`` -- a list ``[ieqs, eqns]``.
355
356
EXAMPLES::
357
358
sage: from sage.geometry.polyhedron.backend_cdd import Polyhedron_RDF_cdd
359
sage: Polyhedron_RDF_cdd(2, [ [(1,0),(0,1),(0,0)], [], []], None, verbose=False)
360
A 2-dimensional polyhedron in RDF^2 defined as the convex hull of 3 vertices
361
"""
362
_cdd_type = 'real'
363
364
_cdd_executable = 'cdd_both_reps'
365
366
def __init__(self, ambient_dim, Vrep, Hrep, **kwds):
367
"""
368
The Python constructor.
369
370
See :class:`Polyhedron_base` for a description of the input
371
data.
372
373
TESTS::
374
375
sage: p = Polyhedron(backend='cddf')
376
sage: type(p)
377
<class 'sage.geometry.polyhedron.backend_cdd.Polyhedron_RDF_cdd'>
378
sage: TestSuite(p).run()
379
"""
380
Polyhedron_cdd.__init__(self, ambient_dim, Vrep, Hrep, **kwds)
381
382
383