Path: blob/master/sage/geometry/polyhedron/backend_cdd.py
4091 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_RDF12from representation import (13PolyhedronRepresentation,14Hrepresentation,15Inequality, Equation,16Vrepresentation,17Vertex, Ray, Line )18192021#########################################################################22class Polyhedron_cdd(Polyhedron_base):23"""24Base class for the cdd backend.25"""2627def _init_from_Vrepresentation(self, ambient_dim, vertices, rays, lines, verbose=False):28"""29Construct polyhedron from V-representation data.3031INPUT:3233- ``ambient_dim`` -- integer. The dimension of the ambient space.3435- ``vertices`` -- list of point. Each point can be specified36as any iterable container of37:meth:`~sage.geometry.polyhedron.base.base_ring` elements.3839- ``rays`` -- list of rays. Each ray can be specified as any40iterable container of41:meth:`~sage.geometry.polyhedron.base.base_ring` elements.4243- ``lines`` -- list of lines. Each line can be specified as44any iterable container of45:meth:`~sage.geometry.polyhedron.base.base_ring` elements.4647- ``verbose`` -- boolean (default: ``False``). Whether to print48verbose output for debugging purposes.4950EXAMPLES::5152sage: Polyhedron(vertices=[(0,0)], rays=[(1,1)],53... lines=[(1,-1)], backend='cddr') # indirect doctest54A 2-dimensional polyhedron in QQ^2 defined as the55convex hull of 1 vertex, 1 ray, 1 line56"""57from cdd_file_format import cdd_Vrepresentation58s = cdd_Vrepresentation(self._cdd_type, vertices, rays, lines)59self._init_from_cdd_input(s, '--reps', verbose)606162def _init_from_Hrepresentation(self, ambient_dim, ieqs, eqns, verbose=False):63"""64Construct polyhedron from H-representation data.6566INPUT:6768- ``ambient_dim`` -- integer. The dimension of the ambient space.6970- ``ieqs`` -- list of inequalities. Each line can be specified71as any iterable container of72:meth:`~sage.geometry.polyhedron.base.base_ring` elements.7374- ``eqns`` -- list of equalities. Each line can be specified75as any iterable container of76:meth:`~sage.geometry.polyhedron.base.base_ring` elements.7778- ``verbose`` -- boolean (default: ``False``). Whether to print79verbose output for debugging purposes.8081EXAMPLES::8283sage: Polyhedron(ieqs=[(0,1,1)], eqns=[(0,1,-1)],84... backend='cddr') # indirect doctest85A 1-dimensional polyhedron in QQ^2 defined as the86convex hull of 1 vertex and 1 ray87"""88from cdd_file_format import cdd_Hrepresentation89s = cdd_Hrepresentation(self._cdd_type, ieqs, eqns)90self._init_from_cdd_input(s, '--reps', verbose)919293def _init_facet_adjacency_matrix(self, verbose=False):94"""95Compute the facet adjacency matrix in case it has not been96computed during initialization.9798EXAMPLES::99100sage: p = Polyhedron(vertices=[(0,0),(1,0),(0,1)], backend='cddr')101sage: '_H_adjacency_matrix' in p.__dict__102False103sage: p._init_facet_adjacency_matrix()104sage: p._H_adjacency_matrix105[0 1 1]106[1 0 1]107[1 1 0]108"""109self._init_from_cdd_input(self.cdd_Hrepresentation(),110'--adjacency', verbose)111112113def _init_vertex_adjacency_matrix(self, verbose=False):114"""115Compute the vertex adjacency matrix in case it has not been116computed during initialization.117118EXAMPLES::119120sage: p = Polyhedron(vertices=[(0,0),(1,0),(0,1)], backend='cddr')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]], backend='cddr')141sage: from sage.geometry.polyhedron.cdd_file_format import cdd_Vrepresentation142sage: s = cdd_Vrepresentation('rational', [[0,0,1],[0,1,0],[1,0,0]], [], [])143sage: p._init_from_cdd_input(s)144sage: p.dim()1452146"""147if verbose: print cdd_input_string148149cdd_proc = Popen([self._cdd_executable, cmdline_arg],150stdin=PIPE, stdout=PIPE, stderr=PIPE)151ans, err = cdd_proc.communicate(input=cdd_input_string)152153# FIXME: check err154if verbose:155print ans156self._init_from_cdd_output(ans)157158159def _init_from_cdd_output(self, cdd_output_string):160"""161Initialize ourselves with the output from cdd.162163TESTS::164165sage: from sage.geometry.polyhedron.cdd_file_format import cdd_Vrepresentation166sage: s = cdd_Vrepresentation('rational',[[0,0],[1,0],[0,1],[1,1]], [], [])167sage: from subprocess import Popen, PIPE168sage: cdd_proc = Popen(['cdd_both_reps_gmp', '--all'], stdin=PIPE, stdout=PIPE, stderr=PIPE)169sage: ans, err = cdd_proc.communicate(input=s)170sage: p = Polyhedron(vertices = [[0,0],[1,0],[0,1],[1,1]], backend='cddr')171sage: p._init_from_cdd_output(ans)172sage: p.vertices()173[[0, 0], [1, 0], [0, 1], [1, 1]]174"""175cddout=cdd_output_string.splitlines()176suppressed_vertex = False # whether cdd suppressed the vertex in output177178# nested function179def expect_in_cddout(expected_string):180l = cddout.pop(0).strip()181if l!=expected_string:182raise ValueError, ('Error while parsing cdd output: expected "'183+expected_string+'" but got "'+l+'".\n' )184# nested function185def cdd_linearities():186l = cddout[0].split()187if l[0] != "linearity":188return []189cddout.pop(0)190assert len(l) == int(l[1])+2, "Not enough linearities given"191return [int(i)-1 for i in l[2:]] # make indices pythonic192193# nested function194def cdd_convert(string, field=self.field()):195"""196Converts the cdd output string to a numerical value.197"""198return [field(x) for x in string.split()]199200# nested function201def find_in_cddout(expected_string):202"""203Find the expected string in a list of strings, and204truncates ``cddout`` to start at that point. Returns205``False`` if search fails.206"""207for pos in range(0,len(cddout)):208l = cddout[pos].strip();209if l==expected_string:210# must not assign to cddout in nested function211for i in range(0,pos+1):212cddout.pop(0)213return True214return False215216if find_in_cddout('V-representation'):217self._Vrepresentation = []218lines = cdd_linearities()219expect_in_cddout('begin')220l = cddout.pop(0).split()221assert self._ambient_dim == int(l[1])-1, "Different ambient dimension?"222suppressed_vertex = True223for i in range(int(l[0])):224l = cddout.pop(0).strip()225l_type = l[0]226l = l[1:]227if i in lines:228Line(self, cdd_convert(l));229elif l_type == '0':230Ray(self, cdd_convert(l));231else:232Vertex(self, cdd_convert(l));233suppressed_vertex = False234if suppressed_vertex and self.n_Vrepresentation()>0:235# cdd does not output the vertex if it is only the origin236Vertex(self, [0] * self._ambient_dim)237self._Vrepresentation = tuple(self._Vrepresentation)238expect_in_cddout('end')239240if find_in_cddout('H-representation'):241self._Hrepresentation = []242equations = cdd_linearities()243expect_in_cddout('begin')244l = cddout.pop(0).split()245assert self._ambient_dim == int(l[1])-1, "Different ambient dimension?"246for i in range(int(l[0])):247l = cddout.pop(0)248if i in equations:249Equation(self, cdd_convert(l));250else:251Inequality(self, cdd_convert(l));252self._Hrepresentation = tuple(self._Hrepresentation)253expect_in_cddout('end')254255# nested function256def cdd_adjacencies():257l = cddout.pop(0).split()258assert l[2] == ':', "Not a line of the adjacency data?"259return [int(i)-1 for i in l[3:]]260261if find_in_cddout('Vertex graph'):262n = len(self._Vrepresentation);263if suppressed_vertex:264n_cdd=n-1;265else:266n_cdd=n;267self._V_adjacency_matrix = matrix(ZZ, n, n, 0)268expect_in_cddout('begin')269l = cddout.pop(0).split()270assert int(l[0]) == n_cdd, "Not enough V-adjacencies in cdd output?"271for i in range(n_cdd):272for a in cdd_adjacencies():273self._V_adjacency_matrix[i,a] = 1274# cdd reports that lines are never adjacent to anything.275# I disagree, they are adjacent to everything!276if self._Vrepresentation[i].is_line():277for j in range(n):278self._V_adjacency_matrix[i,j] = 1279self._V_adjacency_matrix[j,i] = 1280self._V_adjacency_matrix[i,i] = 0281if suppressed_vertex: # cdd implied that there is only one vertex282for i in range(n-1):283self._V_adjacency_matrix[i,n-1] = 1284self._V_adjacency_matrix[n-1,i] = 1285self._V_adjacency_matrix.set_immutable()286expect_in_cddout('end')287288if find_in_cddout('Facet graph'):289n = len(self._Hrepresentation);290self._H_adjacency_matrix = matrix(ZZ, n, n, 0)291expect_in_cddout('begin')292l = cddout.pop(0).split()293assert int(l[0]) == n, "Not enough H-adjacencies in cdd output?"294for i in range(n):295for a in cdd_adjacencies():296self._H_adjacency_matrix[i,a] = 1297self._H_adjacency_matrix.set_immutable()298expect_in_cddout('end')299300301#########################################################################302class Polyhedron_QQ_cdd(Polyhedron_cdd, Polyhedron_QQ):303"""304Polyhedra over QQ with cdd305306INPUT:307308- ``ambient_dim`` -- integer. The dimension of the ambient space.309310- ``Vrep`` -- a list ``[vertices, rays, lines]``.311312- ``Hrep`` -- a list ``[ieqs, eqns]``.313314EXAMPLES::315316sage: from sage.geometry.polyhedron.backend_cdd import Polyhedron_QQ_cdd317sage: Polyhedron_QQ_cdd(2, [ [(1,0),(0,1),(0,0)], [], []], None, verbose=False)318A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 3 vertices319"""320321_cdd_type = 'rational'322323_cdd_executable = 'cdd_both_reps_gmp'324325def __init__(self, ambient_dim, Vrep, Hrep, **kwds):326"""327The Python constructor.328329See :class:`Polyhedron_base` for a description of the input330data.331332TESTS::333334sage: p = Polyhedron(backend='cddr')335sage: type(p)336<class 'sage.geometry.polyhedron.backend_cdd.Polyhedron_QQ_cdd'>337sage: TestSuite(p).run()338"""339Polyhedron_cdd.__init__(self, ambient_dim, Vrep, Hrep, **kwds)340341342#########################################################################343class Polyhedron_RDF_cdd(Polyhedron_cdd, Polyhedron_RDF):344"""345Polyhedra over RDF with cdd346347INPUT:348349- ``ambient_dim`` -- integer. The dimension of the ambient space.350351- ``Vrep`` -- a list ``[vertices, rays, lines]``.352353- ``Hrep`` -- a list ``[ieqs, eqns]``.354355EXAMPLES::356357sage: from sage.geometry.polyhedron.backend_cdd import Polyhedron_RDF_cdd358sage: Polyhedron_RDF_cdd(2, [ [(1,0),(0,1),(0,0)], [], []], None, verbose=False)359A 2-dimensional polyhedron in RDF^2 defined as the convex hull of 3 vertices360"""361_cdd_type = 'real'362363_cdd_executable = 'cdd_both_reps'364365def __init__(self, ambient_dim, Vrep, Hrep, **kwds):366"""367The Python constructor.368369See :class:`Polyhedron_base` for a description of the input370data.371372TESTS::373374sage: p = Polyhedron(backend='cddf')375sage: type(p)376<class 'sage.geometry.polyhedron.backend_cdd.Polyhedron_RDF_cdd'>377sage: TestSuite(p).run()378"""379Polyhedron_cdd.__init__(self, ambient_dim, Vrep, Hrep, **kwds)380381382383