diff --git a/src/sage/geometry/polyhedron/backend_normaliz.py b/src/sage/geometry/polyhedron/backend_normaliz.py index ce8cd97adff..ee3e3e5aebc 100644 --- a/src/sage/geometry/polyhedron/backend_normaliz.py +++ b/src/sage/geometry/polyhedron/backend_normaliz.py @@ -359,7 +359,7 @@ def _init_from_normaliz_data(self, data, normaliz_field=None, verbose=False): sage: p = Polyhedron(backend='normaliz', ambient_dim=2) # optional - pynormaliz sage: from sage.geometry.polyhedron.backend_normaliz import Polyhedron_QQ_normaliz # optional - pynormaliz - sage: data = {'inhom_inequalities': [[-1, 2, 0], [0, 0, 1], [2, -1, 0]]} # optional - pynormaliz + sage: data = {'inhom_inequalities': [[-1, 2, 0], [0, 0, 1], [2, -1, 0]]} # optional - pynormaliz sage: Polyhedron_QQ_normaliz._init_from_normaliz_data(p, data) # optional - pynormaliz sage: p.inequalities_list() # optional - pynormaliz [[0, -1, 2], [0, 2, -1]] @@ -379,7 +379,22 @@ def _init_from_normaliz_data(self, data, normaliz_field=None, verbose=False): """ if normaliz_field is None: normaliz_field = QQ + cone = self._cone_from_normaliz_data(data, verbose) + self._init_from_normaliz_cone(cone, normaliz_field) + + def _cone_from_normaliz_data(self, data, verbose=False): + """ + Construct a normaliz cone from ``data`` (a dictionary). + EXAMPLES:: + + sage: p = Polyhedron(backend='normaliz', ambient_dim=2) # optional - pynormaliz + sage: from sage.geometry.polyhedron.backend_normaliz import Polyhedron_QQ_normaliz # optional - pynormaliz + sage: data = {'inhom_inequalities': [[-1, 2, 0], [0, 0, 1], [2, -1, 0]]} # optional - pynormaliz + sage: cone = Polyhedron_QQ_normaliz._cone_from_normaliz_data(p, data) # optional - pynormaliz + sage: p._nmz_result(cone,'SupportHyperplanes') # optional - pynormaliz + [[-1L, 2L, 0L], [0L, 0L, 1L], [2L, -1L, 0L]] + """ if verbose: import six if isinstance(verbose, six.string_types): @@ -401,8 +416,7 @@ def _init_from_normaliz_data(self, data, normaliz_field=None, verbose=False): import PyNormaliz cone = PyNormaliz.NmzCone(**data) assert cone, "{} did not return a cone".format(_format_function_call('PyNormaliz.NmzCone', **data)) - - self._init_from_normaliz_cone(cone, normaliz_field) + return cone def _is_zero(self, x): """ @@ -630,6 +644,154 @@ def nmz_ieqs_eqns_QQ(ieqs, eqns): data["number_field"] = number_field_data self._init_from_normaliz_data(data, normaliz_field=normaliz_field, verbose=verbose) + def _cone_from_Vrepresentation_and_Hrepresentation(self, vertices, rays, ieqs, eqns, verbose=False): + r""" + Construct cone from V-representation data and H-representation data. + + INPUT: + + - ``vertices`` -- list of point; each point can be specified + as any iterable container of + :meth:`~sage.geometry.polyhedron.base.base_ring` elements + + - ``rays`` -- list of rays; each ray can be specified as any + iterable container of + :meth:`~sage.geometry.polyhedron.base.base_ring` elements + + - ``ieqs`` -- list of inequalities; each line can be specified + as any iterable container of + :meth:`~sage.geometry.polyhedron.base.base_ring` elements + + - ``eqns`` -- list of equalities; each line can be specified + as any iterable container of + :meth:`~sage.geometry.polyhedron.base.base_ring` elements + + - ``verbose`` -- boolean (default: ``False``); whether to print + verbose output for debugging purposes + + EXAMPLES:: + + sage: P = polytopes.hypercube(4,backend='normaliz') * Polyhedron(rays=[[0,1]]) * Polyhedron(lines=[[1,0]]) # optional - pynormaliz + sage: P # optional - pynormaliz + A 6-dimensional polyhedron in ZZ^8 defined as the convex hull of 16 vertices, 1 ray, 1 line + + sage: cone = P._cone_from_Vrepresentation_and_Hrepresentation(P.vertices(),P.rays(),P.inequalities(),P.equations()) # optional - pynormaliz + sage: import PyNormaliz # optional - pynormaliz + sage: PyNormaliz.NmzIsComputed(cone, "VerticesOfPolyhedron") # optional - pynormaliz + True + sage: PyNormaliz.NmzIsComputed(cone, "ExtremeRays") # optional - pynormaliz + True + sage: PyNormaliz.NmzIsComputed(cone, "MaximalSubspace") # optional - pynormaliz + False + sage: PyNormaliz.NmzIsComputed(cone, "SupportHyperplanes") # optional - pynormaliz + True + sage: PyNormaliz.NmzIsComputed(cone, "Equations") # optional - pynormaliz + False + + + TESTS:: + + sage: def test_poly(P): + ....: cone = P._cone_from_Vrepresentation_and_Hrepresentation(P.vertices(),P.rays(),P.inequalities(),P.equations()) + ....: cone2 = P._normaliz_cone + ....: args = ['Equations','VerticesOfPolyhedron','ExtremeRays','SupportHyperplanes','MaximalSubspace'] + ....: return all(P._nmz_result(cone,arg) == P._nmz_result(cone2,arg) for arg in args) + sage: test_poly(polytopes.simplex(backend='normaliz')) # optional - pynormaliz + True + sage: test_poly(polytopes.dodecahedron(backend='normaliz')) # optional - pynormaliz + True + sage: test_poly(Polyhedron(vertices=[[1,0],[0,1]],rays=[[1,1]], backend='normaliz')) # optional - pynormaliz + True + sage: test_poly(Polyhedron(vertices=[[0,0,0],[0,1,1],[1,0,1],[-1,-1,1]],rays=[[0,0,1]], backend='normaliz')) # optional - pynormaliz + True + sage: test_poly(Polyhedron(vertices=[[-1,0],[1,0]],lines=[[0,1]], backend='normaliz')) # optional - pynormaliz + True + """ + def vert_ray_QQ(vertices, rays): + nmz_vertices = [] + for v in vertices: + d = LCM_list([denominator(v_i) for v_i in v]) + dv = [ d*v_i for v_i in v ] + nmz_vertices.append(dv + [d]) + nmz_rays = [] + for r in rays: + d = LCM_list([denominator(r_i) for r_i in r]) + dr = [ d*r_i for r_i in r ] + nmz_rays.append(dr + [0]) + return nmz_vertices, nmz_rays + + def nmz_ieqs_eqns_QQ(ieqs, eqns): + nmz_ieqs = [] + for ieq in ieqs: + d = LCM_list([denominator(ieq_i) for ieq_i in ieq]) + dieq = [ ZZ(d*ieq_i) for ieq_i in ieq ] + b = dieq[0] + A = dieq[1:] + nmz_ieqs.append(A + [b]) + nmz_eqns = [] + for eqn in eqns: + d = LCM_list([denominator(eqn_i) for eqn_i in eqn]) + deqn = [ ZZ(d*eqn_i) for eqn_i in eqn ] + b = deqn[0] + A = deqn[1:] + nmz_eqns.append(A + [b]) + return nmz_ieqs, nmz_eqns + + def vert_ray_NF(vertices, rays): + h_vertices = [ list(v) + [1] for v in vertices ] + h_rays = [ list(r) + [0] for r in rays ] + return h_vertices, h_rays + + def nmz_ieqs_eqns_NF(ieqs, eqns): + nmz_ieqs = [] + for ieq in ieqs: + b = ieq[0] + A = ieq[1:] + nmz_ieqs.append(list(A) + [b]) + nmz_eqns = [] + for eqn in eqns: + b = eqn[0] + A = eqn[1:] + nmz_eqns.append(list(A) + [b]) + return nmz_ieqs, nmz_eqns + + if vertices is None: + vertices = [] + if rays is None: + rays = [] + if ieqs is None: + ieqs = [] + if eqns is None: + eqns = [] + + (nmz_vertices, nmz_rays), normaliz_field \ + = self._compute_nmz_data_lists_and_field((vertices, rays), + vert_ray_QQ, + vert_ray_NF) + + (nmz_ieqs, nmz_eqns), normaliz_field \ + = self._compute_nmz_data_lists_and_field((ieqs, eqns), + nmz_ieqs_eqns_QQ, + nmz_ieqs_eqns_NF) + + if not nmz_vertices and not nmz_rays: + # Special case to avoid: + # error: Some error in the normaliz input data detected: + # All input matrices empty! + return None + else: + data = {"extreme_rays": nmz_vertices + nmz_rays, + "equations": nmz_eqns, + "support_hyperplanes": nmz_ieqs} + + ambient_dim = len(data["extreme_rays"][0]) + data["dehomogenization"] = [[0]*(ambient_dim-1) + [1]] + + number_field_data = self._number_field_triple(normaliz_field) + if number_field_data: + data["number_field"] = number_field_data + return self._cone_from_normaliz_data(data, verbose=verbose) + def _compute_nmz_data_lists_and_field(self, data_lists, convert_QQ, convert_NF): r""" Compute data lists in Normaliz format and the number field to use with Normaliz.