Path: blob/master/src/sage/geometry/polyhedron/backend_cdd.py
8817 views
"""1The cdd backend for polyhedral computations2"""34from subprocess import Popen, PIPE5from sage.rings.all import ZZ, QQ, RDF6from sage.misc.all import SAGE_TMP, tmp_filename, union, cached_method, prod7from sage.matrix.constructor import matrix89from base import Polyhedron_base10from base_QQ import Polyhedron_QQ11from base_RDF import Polyhedron_RDF12131415#########################################################################16class Polyhedron_cdd(Polyhedron_base):17"""18Base class for the cdd backend.19"""2021def _init_from_Vrepresentation(self, vertices, rays, lines, verbose=False):22"""23Construct polyhedron from V-representation data.2425INPUT:2627- ``vertices`` -- list of point. Each point can be specified28as any iterable container of29:meth:`~sage.geometry.polyhedron.base.base_ring` elements.3031- ``rays`` -- list of rays. Each ray can be specified as any32iterable container of33:meth:`~sage.geometry.polyhedron.base.base_ring` elements.3435- ``lines`` -- list of lines. Each line can be specified as36any iterable container of37:meth:`~sage.geometry.polyhedron.base.base_ring` elements.3839- ``verbose`` -- boolean (default: ``False``). Whether to print40verbose output for debugging purposes.4142EXAMPLES::4344sage: Polyhedron(vertices=[(0,0)], rays=[(1,1)],45... lines=[(1,-1)], backend='cdd', base_ring=QQ) # indirect doctest46A 2-dimensional polyhedron in QQ^2 defined as the47convex hull of 1 vertex, 1 ray, 1 line48"""49from cdd_file_format import cdd_Vrepresentation50s = cdd_Vrepresentation(self._cdd_type, vertices, rays, lines)51self._init_from_cdd_input(s, '--reps', verbose)525354def _init_from_Hrepresentation(self, ieqs, eqns, verbose=False):55"""56Construct polyhedron from H-representation data.5758INPUT:5960- ``ieqs`` -- list of inequalities. Each line can be specified61as any iterable container of62:meth:`~sage.geometry.polyhedron.base.base_ring` elements.6364- ``eqns`` -- list of equalities. Each line can be specified65as any iterable container of66:meth:`~sage.geometry.polyhedron.base.base_ring` elements.6768- ``verbose`` -- boolean (default: ``False``). Whether to print69verbose output for debugging purposes.7071EXAMPLES::7273sage: Polyhedron(ieqs=[(0,1,1)], eqns=[(0,1,-1)],74... backend='cdd', base_ring=QQ) # indirect doctest75A 1-dimensional polyhedron in QQ^2 defined as the76convex hull of 1 vertex and 1 ray77"""78from cdd_file_format import cdd_Hrepresentation79s = cdd_Hrepresentation(self._cdd_type, ieqs, eqns)80self._init_from_cdd_input(s, '--reps', verbose)818283def _init_facet_adjacency_matrix(self, verbose=False):84"""85Compute the facet adjacency matrix in case it has not been86computed during initialization.8788INPUT:8990- ``verbose`` -- boolean (default: ``False``). Whether to print91verbose output for debugging purposes.9293EXAMPLES::9495sage: p = Polyhedron(vertices=[(0,0),(1,0),(0,1)], backend='cdd', base_ring=QQ)96sage: '_H_adjacency_matrix' in p.__dict__97False98sage: p._init_facet_adjacency_matrix()99sage: p._H_adjacency_matrix100[0 1 1]101[1 0 1]102[1 1 0]103"""104self._init_from_cdd_input(self.cdd_Hrepresentation(),105'--adjacency', verbose)106107108def _init_vertex_adjacency_matrix(self, verbose=False):109"""110Compute the vertex adjacency matrix in case it has not been111computed during initialization.112113INPUT:114115- ``verbose`` -- boolean (default: ``False``). Whether to print116verbose output for debugging purposes.117118EXAMPLES::119120sage: p = Polyhedron(vertices=[(0,0),(1,0),(0,1)], backend='cdd', base_ring=QQ)121sage: '_V_adjacency_matrix' in p.__dict__122False123sage: p._init_vertex_adjacency_matrix()124sage: p._V_adjacency_matrix125[0 1 1]126[1 0 1]127[1 1 0]128"""129self._init_from_cdd_input(self.cdd_Vrepresentation(),130'--adjacency', verbose)131132133def _init_from_cdd_input(self, cdd_input_string, cmdline_arg='--all', verbose=False):134"""135Internal method: run cdd on a cdd H- or V-representation136and initialize ourselves with the output.137138TESTS::139140sage: p = Polyhedron(vertices=[[0,0,0],[1,0,0],[0,1,0],[0,0,1]],141... backend='cdd', base_ring=QQ)142sage: from sage.geometry.polyhedron.cdd_file_format import cdd_Vrepresentation143sage: s = cdd_Vrepresentation('rational', [[0,0,1],[0,1,0],[1,0,0]], [], [])144sage: p._init_from_cdd_input(s)145sage: p.dim()1462147148sage: point_list = [[0.132, -1.028, 0.028],[0.5, 0.5, -1.5],149... [-0.5, 1.5, -0.5],[0.5, 0.5, 0.5],[1.5, -0.5, -0.5],150... [-0.332, -0.332, -0.668],[-1.332, 0.668, 0.332],151... [-0.932, 0.068, 0.932],[-0.38, -0.38, 1.38],152... [-0.744, -0.12, 1.12],[-0.7781818182, -0.12, 0.9490909091],153... [0.62, -1.38, 0.38],[0.144, -1.04, 0.04],154... [0.1309090909, -1.0290909091, 0.04]]155sage: Polyhedron(point_list)156Traceback (most recent call last):157...158ValueError: *Error: Numerical inconsistency is found. Use the GMP exact arithmetic.159sage: Polyhedron(point_list, base_ring=QQ)160A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 14 vertices161"""162if verbose:163print '---- CDD input -----'164print cdd_input_string165166cdd_proc = Popen([self._cdd_executable, cmdline_arg],167stdin=PIPE, stdout=PIPE, stderr=PIPE)168ans, err = cdd_proc.communicate(input=cdd_input_string)169170if verbose:171print '---- CDD output -----'172print ans173print err174if 'Error:' in ans + err:175# cdd reports errors on stdout and misc information on stderr176raise ValueError(ans.strip())177self._init_from_cdd_output(ans)178179180def _init_from_cdd_output(self, cdd_output_string):181"""182Initialize ourselves with the output from cdd.183184TESTS::185186sage: from sage.geometry.polyhedron.cdd_file_format import cdd_Vrepresentation187sage: s = cdd_Vrepresentation('rational',[[0,0],[1,0],[0,1],[1,1]], [], [])188sage: from subprocess import Popen, PIPE189sage: cdd_proc = Popen(['cdd_both_reps_gmp', '--all'], stdin=PIPE, stdout=PIPE, stderr=PIPE)190sage: ans, err = cdd_proc.communicate(input=s)191sage: p = Polyhedron(vertices = [[0,0],[1,0],[0,1],[1,1]], backend='cdd', base_ring=QQ)192sage: p._init_from_cdd_output(ans)193sage: p.vertices()194(A vertex at (0, 0), A vertex at (1, 0), A vertex at (0, 1), A vertex at (1, 1))195"""196cddout=cdd_output_string.splitlines()197suppressed_vertex = False # whether cdd suppressed the vertex in output198parent = self.parent()199200# nested function201def expect_in_cddout(expected_string):202l = cddout.pop(0).strip()203if l!=expected_string:204raise ValueError, ('Error while parsing cdd output: expected "'205+expected_string+'" but got "'+l+'".\n' )206# nested function207def cdd_linearities():208l = cddout[0].split()209if l[0] != "linearity":210return []211cddout.pop(0)212assert len(l) == int(l[1])+2, "Not enough linearities given"213return [int(i)-1 for i in l[2:]] # make indices pythonic214215# nested function216def cdd_convert(string, field=self.field()):217"""218Converts the cdd output string to a numerical value.219"""220return [field(x) for x in string.split()]221222# nested function223def find_in_cddout(expected_string):224"""225Find the expected string in a list of strings, and226truncates ``cddout`` to start at that point. Returns227``False`` if search fails.228"""229for pos in range(0,len(cddout)):230l = cddout[pos].strip();231if l==expected_string:232# must not assign to cddout in nested function233for i in range(0,pos+1):234cddout.pop(0)235return True236return False237238if find_in_cddout('V-representation'):239self._Vrepresentation = []240lines = cdd_linearities()241expect_in_cddout('begin')242l = cddout.pop(0).split()243assert self.ambient_dim() == int(l[1])-1, "Different ambient dimension?"244suppressed_vertex = True245for i in range(int(l[0])):246l = cddout.pop(0).strip()247l_type = l[0]248l = l[1:]249if i in lines:250parent._make_Line(self, cdd_convert(l));251elif l_type == '0':252parent._make_Ray(self, cdd_convert(l));253else:254parent._make_Vertex(self, cdd_convert(l));255suppressed_vertex = False256if suppressed_vertex and self.n_Vrepresentation()>0:257# cdd does not output the vertex if it is only the origin258parent._make_Vertex(self, [0] * self.ambient_dim())259self._Vrepresentation = tuple(self._Vrepresentation)260expect_in_cddout('end')261262if find_in_cddout('H-representation'):263self._Hrepresentation = []264equations = cdd_linearities()265expect_in_cddout('begin')266l = cddout.pop(0).split()267assert self.ambient_dim() == int(l[1])-1, "Different ambient dimension?"268for i in range(int(l[0])):269l = cddout.pop(0)270if i in equations:271parent._make_Equation(self, cdd_convert(l));272else:273parent._make_Inequality(self, cdd_convert(l));274self._Hrepresentation = tuple(self._Hrepresentation)275expect_in_cddout('end')276277# nested function278def cdd_adjacencies():279l = cddout.pop(0).split()280assert l[2] == ':', "Not a line of the adjacency data?"281return [int(i)-1 for i in l[3:]]282283if find_in_cddout('Vertex graph'):284n = len(self._Vrepresentation);285if suppressed_vertex:286n_cdd=n-1;287else:288n_cdd=n;289self._V_adjacency_matrix = matrix(ZZ, n, n, 0)290expect_in_cddout('begin')291l = cddout.pop(0).split()292assert int(l[0]) == n_cdd, "Not enough V-adjacencies in cdd output?"293for i in range(n_cdd):294for a in cdd_adjacencies():295self._V_adjacency_matrix[i,a] = 1296# cdd reports that lines are never adjacent to anything.297# I disagree, they are adjacent to everything!298if self._Vrepresentation[i].is_line():299for j in range(n):300self._V_adjacency_matrix[i,j] = 1301self._V_adjacency_matrix[j,i] = 1302self._V_adjacency_matrix[i,i] = 0303if suppressed_vertex: # cdd implied that there is only one vertex304for i in range(n-1):305self._V_adjacency_matrix[i,n-1] = 1306self._V_adjacency_matrix[n-1,i] = 1307self._V_adjacency_matrix.set_immutable()308expect_in_cddout('end')309310if find_in_cddout('Facet graph'):311n = len(self._Hrepresentation);312self._H_adjacency_matrix = matrix(ZZ, n, n, 0)313expect_in_cddout('begin')314l = cddout.pop(0).split()315assert int(l[0]) == n, "Not enough H-adjacencies in cdd output?"316for i in range(n):317for a in cdd_adjacencies():318self._H_adjacency_matrix[i,a] = 1319self._H_adjacency_matrix.set_immutable()320expect_in_cddout('end')321322323#########################################################################324class Polyhedron_QQ_cdd(Polyhedron_cdd, Polyhedron_QQ):325"""326Polyhedra over QQ with cdd327328INPUT:329330- ``parent`` -- the parent, an instance of331:class:`~sage.geometry.polyhedron.parent.Polyhedra`.332333- ``Vrep`` -- a list ``[vertices, rays, lines]`` or ``None``.334335- ``Hrep`` -- a list ``[ieqs, eqns]`` or ``None``.336337EXAMPLES::338339sage: from sage.geometry.polyhedron.parent import Polyhedra340sage: parent = Polyhedra(QQ, 2, backend='cdd')341sage: from sage.geometry.polyhedron.backend_cdd import Polyhedron_QQ_cdd342sage: Polyhedron_QQ_cdd(parent, [ [(1,0),(0,1),(0,0)], [], []], None, verbose=False)343A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 3 vertices344"""345346_cdd_type = 'rational'347348_cdd_executable = 'cdd_both_reps_gmp'349350def __init__(self, parent, Vrep, Hrep, **kwds):351"""352The Python constructor.353354See :class:`Polyhedron_base` for a description of the input355data.356357TESTS::358359sage: p = Polyhedron(backend='cdd', base_ring=QQ)360sage: type(p)361<class 'sage.geometry.polyhedron.backend_cdd.Polyhedra_QQ_cdd_with_category.element_class'>362sage: TestSuite(p).run()363"""364Polyhedron_cdd.__init__(self, parent, Vrep, Hrep, **kwds)365366367#########################################################################368class Polyhedron_RDF_cdd(Polyhedron_cdd, Polyhedron_RDF):369"""370Polyhedra over RDF with cdd371372INPUT:373374- ``ambient_dim`` -- integer. The dimension of the ambient space.375376- ``Vrep`` -- a list ``[vertices, rays, lines]`` or ``None``.377378- ``Hrep`` -- a list ``[ieqs, eqns]`` or ``None``.379380EXAMPLES::381382sage: from sage.geometry.polyhedron.parent import Polyhedra383sage: parent = Polyhedra(RDF, 2, backend='cdd')384sage: from sage.geometry.polyhedron.backend_cdd import Polyhedron_RDF_cdd385sage: Polyhedron_RDF_cdd(parent, [ [(1,0),(0,1),(0,0)], [], []], None, verbose=False)386A 2-dimensional polyhedron in RDF^2 defined as the convex hull of 3 vertices387"""388_cdd_type = 'real'389390_cdd_executable = 'cdd_both_reps'391392def __init__(self, parent, Vrep, Hrep, **kwds):393"""394The Python constructor.395396See :class:`Polyhedron_base` for a description of the input397data.398399TESTS::400401sage: p = Polyhedron(backend='cdd', base_ring=RDF)402sage: type(p)403<class 'sage.geometry.polyhedron.backend_cdd.Polyhedra_RDF_cdd_with_category.element_class'>404sage: TestSuite(p).run()405"""406Polyhedron_cdd.__init__(self, parent, Vrep, Hrep, **kwds)407408409410