def cone(self): r""" Return the cone defined by `A`. This method is for debugging only. Assumes that the base ring is `\QQ`. OUTPUT: The cone defined by the inequalities as a :func:`~sage.geometry.polyhedron.constructor.Polyhedron`, using the PPL backend. EXAMPLES:: sage: from sage.geometry.polyhedron.double_description import StandardAlgorithm sage: A = matrix(QQ, [(1,0,1), (0,1,1), (-1,-1,1)]) sage: DD, _ = StandardAlgorithm(A).initial_pair() sage: DD.cone().Hrepresentation() (An inequality (-1, -1, 1) x + 0 >= 0, An inequality (0, 1, 1) x + 0 >= 0, An inequality (1, 0, 1) x + 0 >= 0) """ from sage.geometry.polyhedron.constructor import Polyhedron assert self.problem.base_ring() == QQ # required for PPL backend if not self.A: return Polyhedron(vertices=[[0] * self.problem.dim()], backend='ppl') else: ieqs = [[0] + list(a) for a in self.A] return Polyhedron(ieqs=ieqs, base_ring=self.problem.base_ring(), backend='ppl')
def verify(self): r""" Validate the double description pair. This method used the PPL backend to check that the double description pair is valid. An assertion is triggered if it is not. Does nothing if the base ring is not `\QQ`. EXAMPLES:: sage: from sage.geometry.polyhedron.double_description import \ ....: DoubleDescriptionPair, Problem sage: A = matrix(QQ, [(1,0,1), (0,1,1), (-1,-1,1)]) sage: alg = Problem(A) sage: DD = DoubleDescriptionPair(alg, ....: [(1, 0, 3), (0, 1, 1), (-1, -1, 1)], ....: [(2/3, -1/3, 1/3), (-1/3, 2/3, 1/3), (-1/3, -1/3, 1/3)]) sage: DD.verify() Traceback (most recent call last): ... assert A_cone == R_cone AssertionError """ from sage.geometry.polyhedron.constructor import Polyhedron if self.problem.base_ring() is not QQ: return A_cone = self.cone() R_cone = Polyhedron(vertices=[[self.zero] * self.problem.dim()], rays=self.R, base_ring=self.problem.base_ring(), backend='ppl') assert A_cone == R_cone assert A_cone.n_inequalities() <= len(self.A) assert R_cone.n_rays() == len(self.R)
def arp_polyhedron(d=3): r""" Return the d-dimensional 1-cylinders of the ARP algorithm. EXAMPLES:: sage: from slabbe.matrix_cocycle import arp_polyhedron sage: A,P,L = arp_polyhedron(3) sage: A.vertices_list() [[0, 0, 0], [1/2, 1/2, 0], [1/2, 1/4, 1/4], [1, 0, 0]] sage: P.vertices_list() [[0, 0, 0], [1/2, 1/2, 0], [1/2, 1/4, 1/4], [1/3, 1/3, 1/3]] :: sage: A,P,L = arp_polyhedron(4) sage: A.vertices_list() [[0, 0, 0, 0], [1/2, 1/2, 0, 0], [1/2, 1/6, 1/6, 1/6], [1/2, 1/4, 1/4, 0], [1, 0, 0, 0]] sage: P.vertices_list() [[0, 0, 0, 0], [1/2, 1/2, 0, 0], [1/2, 1/4, 1/4, 0], [1/2, 1/6, 1/6, 1/6], [1/4, 1/4, 1/4, 1/4], [1/3, 1/3, 1/3, 0]] :: sage: A,P,L = arp_polyhedron(5) sage: A.vertices_list() [[0, 0, 0, 0, 0], [1/2, 1/2, 0, 0, 0], [1/2, 1/8, 1/8, 1/8, 1/8], [1/2, 1/6, 1/6, 1/6, 0], [1/2, 1/4, 1/4, 0, 0], [1, 0, 0, 0, 0]] sage: P.vertices_list() [[0, 0, 0, 0, 0], [1/2, 1/2, 0, 0, 0], [1/2, 1/6, 1/6, 1/6, 0], [1/2, 1/8, 1/8, 1/8, 1/8], [1/2, 1/4, 1/4, 0, 0], [1/3, 1/3, 1/3, 0, 0], [1/5, 1/5, 1/5, 1/5, 1/5], [1/4, 1/4, 1/4, 1/4, 0]] """ from sage.geometry.polyhedron.constructor import Polyhedron positive = [ [0]*i + [1] + [0]*(d-i) for i in range(1, d+1)] atmostone = [[1] + [-1]*d] ieq_arnoux = [[0]+[1]+[-1]*(d-1)] ieq_arnoux_not = [[0]+[-1]+[1]*(d-1)] ieq_sorted = [ [0]*i + [1,-1] + [0]*(d-i-1) for i in range(1,d)] A = Polyhedron(ieqs=positive + atmostone + ieq_sorted + ieq_arnoux) P = Polyhedron(ieqs=positive + atmostone + ieq_sorted + ieq_arnoux_not) L = Polyhedron(ieqs=positive + atmostone + ieq_sorted) return A,P,L
def is_Z3_convergent(a, b, c, d, e, f, g): r""" TESTS:: sage: from surface_dynamics.misc.generalized_multiple_zeta_values import is_Z3_convergent Convergent examples:: sage: assert is_Z3_convergent(2,0,2,2,0,0,0) sage: assert is_Z3_convergent(0,0,0,0,0,0,4) sage: assert is_Z3_convergent(1,0,0,1,0,0,2) sage: assert is_Z3_convergent(0,1,0,1,0,0,2) sage: assert is_Z3_convergent(0,1,0,0,0,1,2) Divergent examples:: sage: assert not is_Z3_convergent(0,0,0,1,1,1,0) sage: assert not is_Z3_convergent(0,0,0,0,0,0,3) """ from sage.geometry.polyhedron.constructor import Polyhedron x, y, z = ZZ['x,y,z'].gens() poly = x**a * y**b * z**c * (x + y)**d * (x + z)**e * (y + z)**f * (x + y + z)**g newton_polytope = Polyhedron(vertices=poly.exponents(), rays=[(-1, 0, 0), (0, -1, 0), (0, 0, -1)]) V = newton_polytope.intersection(Polyhedron(rays=[(1, 1, 1)])).vertices() r = max(max(v.vector()) for v in V) return r > 1
def populate_polyhedra(self): from sage.geometry.polyhedron.constructor import Polyhedron from sage.symbolic.ring import SR def get_vector(inequality, vars): coefficients = list(inequality.coefficient(var) for var in vars) constant = inequality - sum(c*v for c, v in zip(coefficients, vars)) return [constant] + coefficients d = self.dimension() prefix = self.trees[0].PREFIX vars = list(SR(prefix + "{}".format(j)) for j in range(d+1)) for tree in self.trees: others = list(self.trees) others.remove(tree) ineqs = [other.partition_cost() - tree.partition_cost() for other in others] + vars ineq_matrix = [get_vector(ineq, vars) for ineq in ineqs] P = Polyhedron(ieqs=ineq_matrix) if self.is_disjoint(): P = polyhedron_break_tie(P) tree.polyhedron = P nonnegative_orthant = Polyhedron(ieqs=[dd*(0,) + (1,) + (d+1-dd)*(0,) for dd in range(1, d+1+1)]) assert all(A.polyhedron & nonnegative_orthant == A.polyhedron for A in self.trees) if self.is_disjoint(): assert all((A.polyhedron & B.polyhedron).is_empty() for A in self.trees for B in self.trees if A != B)
def verify(self, inequalities, equations): """ Compare result to PPL if the base ring is QQ. This method is for debugging purposes and compares the computation with another backend if available. INPUT: - ``inequalities``, ``equations`` -- see :class:`Hrep2Vrep`. EXAMPLES:: sage: from sage.geometry.polyhedron.double_description_inhomogeneous import Hrep2Vrep sage: H = Hrep2Vrep(QQ, 1, [(1,2)], []) sage: H.verify([(1,2)], []) """ from sage.rings.all import QQ from sage.geometry.polyhedron.constructor import Polyhedron if self.base_ring is not QQ: return P = Polyhedron(vertices=self.vertices, rays=self.rays, lines=self.lines, base_ring=QQ, ambient_dim=self.dim, backend='ppl') Q = Polyhedron(ieqs=inequalities, eqns=equations, base_ring=QQ, ambient_dim=self.dim, backend='ppl') if (P != Q) or \ (len(self.vertices) != P.n_vertices()) or \ (len(self.rays) != P.n_rays()) or \ (len(self.lines) != P.n_lines()): print('incorrect!', end="") print(Q.Vrepresentation()) print(P.Hrepresentation())
def compute_monomials(R, nverts, dresverts): """Eq. A.8 from arXiv:1411.1418""" X = np.array(R.gens()) Delta = Polyhedron(vertices=nverts) npoints = np.array(Delta.integral_points()) P_expon = (npoints @ dresverts.T) + 1 P_monoms = np.power(X, P_expon).prod(axis=1) return P_monoms
def cassaigne_polyhedron(d=3): r""" Return the d-dimensional 1-cylinders of the Cassaigne algorithm. (of the dual!) EXAMPLES:: sage: from slabbe.matrix_cocycle import cassaigne_polyhedron sage: L,La,Lb = cassaigne_polyhedron(3) sage: L.vertices_list() [[0, 0, 0], [0, 1/2, 1/2], [1/3, 1/3, 1/3], [1/2, 1/2, 0]] sage: La.vertices_list() [[0, 0, 0], [0, 1/2, 1/2], [1/3, 1/3, 1/3], [1/4, 1/2, 1/4]] sage: Lb.vertices_list() [[0, 0, 0], [1/3, 1/3, 1/3], [1/2, 1/2, 0], [1/4, 1/2, 1/4]] :: sage: L,La,Lb = cassaigne_polyhedron(4) sage: L.vertices_list() [[0, 0, 0, 0], [0, 1/3, 1/3, 1/3], [1/3, 1/3, 1/3, 0], [1/4, 1/4, 1/4, 1/4], [1/5, 2/5, 1/5, 1/5], [1/5, 1/5, 2/5, 1/5]] :: sage: L,La,Lb = cassaigne_polyhedron(5) sage: L.vertices_list() [[0, 0, 0, 0, 0], [0, 1/4, 1/4, 1/4, 1/4], [1/4, 1/4, 1/4, 1/4, 0], [1/6, 1/6, 1/3, 1/6, 1/6], [1/5, 1/5, 1/5, 1/5, 1/5], [1/6, 1/3, 1/6, 1/6, 1/6], [1/7, 2/7, 2/7, 1/7, 1/7], [1/7, 2/7, 1/7, 2/7, 1/7], [1/7, 1/7, 2/7, 2/7, 1/7], [1/6, 1/6, 1/6, 1/3, 1/6]] """ from sage.geometry.polyhedron.constructor import Polyhedron # [-1,7,3,4] represents the inequality 7x_1+3x_2+4x_3>= 1. positive = [ [0]*i + [1] + [0]*(d-i) for i in range(1, d+1)] atmostone = [[1] + [-1]*d] ai_lt_a1d = [[0]+[1]+[0]*(i-2)+[-1]+[0]*(d-i-1)+[1] for i in range(2,d)] ai_gt_a1 = [[0]+[-1]+[0]*(i-2)+[1]+[0]*(d-i-1)+[0] for i in range(2,d)] ai_gt_ad = [[0]+[0]+[0]*(i-2)+[1]+[0]*(d-i-1)+[-1] for i in range(2,d)] a1_gt_ad = [[0]+[1]+[0]*(d-2)+[-1]] a1_lt_ad = [[0]+[-1]+[0]*(d-2)+[1]] L = Polyhedron(ieqs=positive + atmostone + ai_lt_a1d + ai_gt_a1 + ai_gt_ad) La = Polyhedron(ieqs=positive+atmostone+ai_lt_a1d+ai_gt_a1+ai_gt_ad+a1_lt_ad) Lb = Polyhedron(ieqs=positive+atmostone+ai_lt_a1d+ai_gt_a1+ai_gt_ad+a1_gt_ad) return L, La, Lb
def verify(self, inequalities, equations): """ Compare result to PPL if the base ring is QQ. This method is for debugging purposes and compares the computation with another backend if available. INPUT: - ``inequalities``, ``equations`` -- see :class:`Hrep2Vrep`. EXAMPLES:: sage: from sage.geometry.polyhedron.double_description_inhomogeneous import Hrep2Vrep sage: H = Hrep2Vrep(QQ, 1, [(1,2)], []) sage: H.verify([(1,2)], []) """ from sage.rings.all import QQ from sage.geometry.polyhedron.constructor import Polyhedron if self.base_ring is not QQ: return P = Polyhedron(vertices=self.vertices, rays=self.rays, lines=self.lines, base_ring=QQ, ambient_dim=self.dim, backend='ppl') Q = Polyhedron(ieqs=inequalities, eqns=equations, base_ring=QQ, ambient_dim=self.dim, backend='ppl') if (P != Q) or \ (len(self.vertices) != P.n_vertices()) or \ (len(self.rays) != P.n_rays()) or \ (len(self.lines) != P.n_lines()): print 'incorrect!', print Q.Vrepresentation() print P.Hrepresentation()
def is_convergent(n, den): r""" TESTS:: sage: import itertools sage: from surface_dynamics.misc.generalized_multiple_zeta_values import is_convergent sage: V = FreeModule(ZZ, 3) sage: va = V((1,0,0)); va.set_immutable() sage: vb = V((0,1,0)); vb.set_immutable() sage: vc = V((0,0,1)); vc.set_immutable() sage: vd = V((1,1,0)); vd.set_immutable() sage: ve = V((1,0,1)); ve.set_immutable() sage: vf = V((0,1,1)); vf.set_immutable() sage: vg = V((1,1,1)); vg.set_immutable() sage: gens = [va,vb,vc,vd,ve,vf,vg] sage: N = 0 sage: for p in itertools.product([0,1,2], repeat=7): # optional: mzv ....: if sum(map(bool,p)) == 3 and is_convergent(3, list(zip(gens,p))): ....: print(p) ....: N += 1 (0, 0, 0, 0, 1, 1, 2) (0, 0, 0, 0, 1, 2, 1) (0, 0, 0, 0, 1, 2, 2) (0, 0, 0, 0, 2, 1, 1) (0, 0, 0, 0, 2, 1, 2) (0, 0, 0, 0, 2, 2, 1) (0, 0, 0, 0, 2, 2, 2) (0, 0, 0, 1, 0, 1, 2) ... (2, 0, 2, 0, 0, 2, 0) (2, 0, 2, 2, 0, 0, 0) (2, 1, 0, 0, 0, 0, 2) (2, 1, 0, 0, 0, 2, 0) (2, 2, 0, 0, 0, 0, 2) (2, 2, 0, 0, 0, 2, 0) (2, 2, 0, 0, 2, 0, 0) (2, 2, 2, 0, 0, 0, 0) sage: print(N) # optional: mzv 125 """ from sage.geometry.polyhedron.constructor import Polyhedron from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing assert all(len(v) == n for v, p in den), (n, den) # TODO: fast code path R = PolynomialRing(QQ, 'x', n) x = R.gens() den_poly = prod(linear_form(R, v)**p for v, p in den) newton_polytope = Polyhedron(vertices=den_poly.exponents(), rays=negative_rays(n)) V = newton_polytope.intersection(Polyhedron(rays=[[1] * n])).vertices() r = max(max(v.vector()) for v in V) return r > 1
def cone_triangulate(C, hyperplane=None): r""" Triangulation of rational cone contained in the positive quadrant. EXAMPLES:: sage: from surface_dynamics.misc.linalg import cone_triangulate sage: P = Polyhedron(rays=[(1,0,0),(0,1,0),(1,0,1),(0,1,1)]) sage: list(cone_triangulate(P)) # random [[(0, 1, 1), (0, 1, 0), (1, 0, 0)], [(0, 1, 1), (1, 0, 1), (1, 0, 0)]] sage: len(_) 2 sage: rays = [(0, 1, 0, -1, 0, 0), ....: (1, 0, -1, 0, 0, -1), ....: (0, 1, -1, 0, 0, -1), ....: (0, 0, 1, 0, 0, 0), ....: (0, 0, 0, 1, 0, -1), ....: (1, -1, 0, 0, 1, -1), ....: (0, 0, 0, 0, 1, -1), ....: (0, 0, 1, -1, 1, 0), ....: (0, 0, 1, -1, 0, 0), ....: (0, 0, 1, 0, -1, 0), ....: (0, 0, 0, 1, -1, -1), ....: (1, -1, 0, 0, 0, -1), ....: (0, 0, 0, 0, 0, -1)] sage: P = Polyhedron(rays=rays) sage: list(cone_triangulate(P, hyperplane=(1, 2, 3, -1, 0, -5))) # random [[(0, 0, 0, 0, 0, -1), (0, 0, 0, 0, 1, -1), (0, 0, 0, 1, -1, -1), (0, 0, 1, 0, 0, 0), (0, 1, -1, 0, 0, -1), (1, -1, 0, 0, 1, -1)], ... (0, 0, 1, 0, 0, 0), (0, 1, -1, 0, 0, -1), (0, 1, 0, -1, 0, 0), (1, -1, 0, 0, 1, -1), (1, 0, -1, 0, 0, -1)]] sage: len(_) 16 """ rays = [r.vector() for r in C.rays()] dim = len(rays[0]) if hyperplane is None: hyperplane = [1] * dim scalings = [sum(x * h for x, h in zip(r, hyperplane)) for r in rays] assert all(s > 0 for s in scalings) normalized_rays = [r / s for r, s in zip(rays, scalings)] P = Polyhedron(vertices=normalized_rays) for t in P.triangulate(): simplex = [P.Vrepresentation(i).vector() for i in t] yield [(r / gcd(r)).change_ring(ZZ) for r in simplex]
def family_two(n, backend=None): r""" Return the vector configuration of the simplicial arrangement `A(n,1)` from the family `\mathcal R(1)` in Grunbaum's list [Gru]_. The arrangement will have an ``n`` hyperplanes, with ``n`` even, consisting of the edges of the regular `n/2`-gon and the `n/2` lines of mirror symmetry. INPUT: - ``n`` -- integer. ``n`` `\geq 6`. The number of lines in the arrangement. - ``backend`` -- string (default = ``None``). The backend to use. OUTPUT: A vector configuration. EXAMPLES:: sage: from cn_hyperarr.infinite_families import * sage: pf = family_two(8,'normaliz'); pf # optional - pynormaliz Vector configuration of 8 vectors in dimension 3 The number of lines must be even:: sage: pf3 = family_two(3,'normaliz'); # optional - pynormaliz Traceback (most recent call last): ... AssertionError: n must be even The number of lines must be at least 6:: sage: pf4 = family_two(4,'normaliz') # optional - pynormaliz Traceback (most recent call last): ... ValueError: n (=2) must be an integer greater than 2 """ assert n % 2 == 0, "n must be even" reg_poly = polytopes.regular_polygon(n / QQ(2), backend='normaliz') reg_cone = Polyhedron( rays=[list(v.vector()) + [1] for v in reg_poly.vertices()], backend=backend) vecs = [h.A() for h in reg_cone.Hrepresentation()] z = QQbar.zeta(n) vecs += [[(z**k).real(), (z**k).imag(), 0] for k in range(n / QQ(2))] return VectorConfiguration(vecs, backend=backend)
def taut_rays(tri, angle): # get the extreme rays of the taut cone - note that the returned # vectors are non-negative because they "point up" N = edge_equation_matrix_taut(tri, angle) N = Matrix(N) dim = N.dimensions()[1] elem_ieqs = [[0] + list(elem_vector(i, dim)) for i in range(dim)] N_rows = [v.list() for v in N.rows()] N_eqns = [[0] + v for v in N_rows] P = Polyhedron(ieqs = elem_ieqs, eqns = N_eqns) rays = [ray.vector() for ray in P.rays()] for ray in rays: assert all(a.is_integer() for a in ray) # all of the entries are integers, represented in QQ, so we clean them. return [vector(ZZ(a) for a in ray) for ray in rays]
def platonic_dodecahedron(): r"""Produce a triple consisting of a polyhedral version of the platonic dodecahedron, the associated cone surface, and a ConeSurfaceToPolyhedronMap from the surface to the polyhedron. EXAMPLES:: sage: from flatsurf.geometry.polyhedra import platonic_dodecahedron sage: polyhedron,surface,surface_to_polyhedron = platonic_dodecahedron() sage: TestSuite(surface).run() r""" vertices = [] phi = AA(1 + sqrt(5)) / 2 F = NumberField(phi.minpoly(), "phi", embedding=phi) phi = F.gen() for x in range(-1, 3, 2): for y in range(-1, 3, 2): for z in range(-1, 3, 2): vertices.append(vector(F, (x, y, z))) for x in range(-1, 3, 2): for y in range(-1, 3, 2): vertices.append(vector(F, (0, x * phi, y / phi))) vertices.append(vector(F, (y / phi, 0, x * phi))) vertices.append(vector(F, (x * phi, y / phi, 0))) scale = AA(2 / sqrt(1 + (phi - 1)**2 + (1 / phi - 1)**2)) p = Polyhedron(vertices=vertices) s, m = polyhedron_to_cone_surface(p, scaling_factor=scale) return p, s, m
def platonic_icosahedron(): r"""Produce a triple consisting of a polyhedral version of the platonic icosahedron, the associated cone surface, and a ConeSurfaceToPolyhedronMap from the surface to the polyhedron. EXAMPLES:: sage: from flatsurf.geometry.polyhedra import platonic_icosahedron sage: polyhedron,surface,surface_to_polyhedron = platonic_icosahedron() sage: TestSuite(surface).run() r""" vertices = [] phi = AA(1 + sqrt(5)) / 2 F = NumberField(phi.minpoly(), "phi", embedding=phi) phi = F.gen() for i in range(3): for s1 in range(-1, 3, 2): for s2 in range(-1, 3, 2): p = 3 * [None] p[i] = s1 * phi p[(i + 1) % 3] = s2 p[(i + 2) % 3] = 0 vertices.append(vector(F, p)) p = Polyhedron(vertices=vertices) s, m = polyhedron_to_cone_surface(p) return p, s, m
def random_interior_point(self, a=10, integer=False): r""" Return a random interior point of a polytope. INPUT: - ``a`` -- number, amplitude of random deplacement in the direction of each ray. - ``integer`` -- bool, whether the output must be with integer coordinates EXEMPLES:: sage: from slabbe.combinat import random_interior_point sage: p = polytopes.hypercube(3) sage: p = p + vector([20,0,0]) sage: p.center() (20, 0, 0) sage: random_interior_point(p) # random (19.33174562788114, -0.5428002756082744, -0.3568284089832092) sage: random_interior_point(p) # random (20.039169786976075, -0.4121594862234468, -0.05623023234688396) sage: random_interior_point(p, integer=True) # random (21, 0, 0) """ from sage.geometry.polyhedron.constructor import Polyhedron L = list(self.vertices()) L.extend(a * random() * ray.vector() for ray in self.rays()) P = Polyhedron(L) return random_interior_point_compact_polytope(P)
def opposite_polyhedron(P, base_ring=None): r"""Generate the polyhedron whose vertices are oppositve to a given one. The opposite polyhedron `-P` is defined as the polyhedron such that `x \in -P` if and only if `-x \in P`. INPUT: * ``P`` - an object of class Polyhedron. * ``base_ring`` - (default: that of P). The ``base_ring`` passed to construct `-P`. OUTPUT: A polyhedron whose vertices are opposite to those of `P`. EXAMPLES:: sage: from polyhedron_tools.misc import BoxInfty, opposite_polyhedron sage: P = BoxInfty([1,1], 0.5) sage: minusP = opposite_polyhedron(P) sage: P.plot(aspect_ratio=1) + minusP.plot() # not tested (plot) TO-DO: The possibility to receive P in matrix form `(A, b)`. """ if base_ring is None: base_ring = P.base_ring() return Polyhedron(vertices=[-1 * vector(v) for v in P.vertices_list()], base_ring=base_ring)
def intersection(self, other): r""" The intersection of ``self`` with ``other``. INPUT: - ``other`` -- a hyperplane, a polyhedron, or something that defines a polyhedron OUTPUT: A polyhedron. EXAMPLES:: sage: H.<x,y,z> = HyperplaneArrangements(QQ) sage: h = x + y + z - 1 sage: h.intersection(x - y) A 1-dimensional polyhedron in QQ^3 defined as the convex hull of 1 vertex and 1 line sage: h.intersection(polytopes.cube()) A 2-dimensional polyhedron in QQ^3 defined as the convex hull of 3 vertices """ from sage.geometry.polyhedron.base import is_Polyhedron from sage.geometry.polyhedron.constructor import Polyhedron if not is_Polyhedron(other): try: other = other.polyhedron() except AttributeError: other = Polyhedron(other) return self.polyhedron().intersection(other)
def polyhedron_break_tie(polyhedron, undo=False): from sage.geometry.polyhedron.constructor import Polyhedron if polyhedron.equations(): raise NotImplementedError return Polyhedron(ieqs=[break_tie(tuple(ieq), undo=undo) for ieq in polyhedron.inequalities()])
def split_polyhedra(dim): r""" :: sage: from partitioner import split_polyhedra, repr_pretty_Hrepresentation sage: for P in split_polyhedra(2): ....: print(repr_pretty_Hrepresentation(P, strict_inequality=True, ....: prefix='s')) s1 > s0 s0 >= s1 sage: for P in split_polyhedra(3): ....: print(repr_pretty_Hrepresentation(P, strict_inequality=True, ....: prefix='s')) s1 >= s0, s2 > s1 s2 > s0, s1 >= s2 s2 > s0, s0 > s1 s2 > s1, s0 >= s2 s1 >= s0, s0 >= s2 s1 >= s2, s0 > s1 sage: for P in split_polyhedra(4): ....: print(repr_pretty_Hrepresentation(P, strict_inequality=True, ....: prefix='s')) s1 >= s0, s2 > s1, s3 > s2 s1 >= s0, s3 > s1, s2 >= s3 s2 >= s0, s3 > s1, s1 >= s2 s2 >= s0, s3 > s2, s1 >= s3 s3 > s0, s2 > s1, s1 >= s3 s3 > s0, s2 >= s3, s1 >= s2 s2 >= s0, s3 > s2, s0 > s1 s3 > s0, s2 >= s3, s0 > s1 s3 > s0, s2 > s1, s0 > s2 s2 > s1, s3 > s2, s0 >= s3 s2 >= s0, s3 > s1, s0 >= s3 s3 > s1, s2 >= s3, s0 > s2 s1 >= s0, s3 > s1, s0 > s2 s3 > s0, s1 >= s3, s0 > s2 s3 > s0, s1 >= s2, s0 > s1 s3 > s1, s1 >= s2, s0 >= s3 s1 >= s0, s3 > s2, s0 >= s3 s3 > s2, s1 >= s3, s0 > s1 s1 >= s0, s2 > s1, s0 >= s3 s2 >= s0, s1 >= s2, s0 >= s3 s2 >= s0, s1 >= s3, s0 > s1 s2 > s1, s1 >= s3, s0 > s2 s1 >= s0, s2 >= s3, s0 > s2 s2 >= s3, s1 >= s2, s0 > s1 """ from sage.combinat.permutation import Permutations from sage.geometry.polyhedron.constructor import Polyhedron return iter( polyhedron_break_tie( Polyhedron( ieqs=[tuple(1 if i==b else (-1 if i==a else 0) for i in range(dim+1)) for a, b in zip(pi[:-1], pi[1:])])) for pi in Permutations(dim))
def polytope(self, P=None): """ Return a polytope of ``self``. INPUT: - ``P`` -- (optional) a space to realize the polytope; default is the weight lattice realization of the crystal EXAMPLES:: sage: MV = crystals.infinity.MVPolytopes(['C', 3]) sage: b = MV.module_generators[0].f_string([3,2,3,2,1]) sage: P = b.polytope(); P A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 6 vertices sage: P.vertices() (A vertex at (0, 0, 0), A vertex at (0, 1, -1), A vertex at (0, 1, 1), A vertex at (1, -1, 0), A vertex at (1, 1, -2), A vertex at (1, 1, 2)) """ if P is None: P = self.parent().weight_lattice_realization() from sage.geometry.polyhedron.constructor import Polyhedron return Polyhedron([v.to_vector() for v in self._polytope_vertices(P)])
def line_vertices(self): r""" Return the vertices for each line in a 3-d acyclic vector_configuration. NOTE: An acyclic vector configuration corresponds to the normal vectors of a hyperplane arrangement with a selected base region. OUTPUT: A list of pairs. EXAMPLES:: sage: from cn_hyperarr.vector_classes import * sage: vc = VectorConfiguration([[1,0,0],[0,1,0],[0,0,1],[1,1,0],[0,1,1],[1,1,1]]) sage: vc.line_vertices() [(0, 1), (1, 2), (2, 3), (0, 4)] The vectors [-1,0,1] and [1,0,1] are the vertices of the line containing [0,0,1]:: sage: vc = VectorConfiguration([[0,0,1],[-1,0,1],[1,0,1]]) sage: vc.line_vertices() [(1, 2)] """ assert self.is_acyclic(), "The vector configuration should be acyclic" nb_pts = self.n_vectors() cocircuits = self.three_dim_cocircuits() list_verts = [] for coc in cocircuits: zero_indices = coc[1] if len(zero_indices) > 2: the_cone = Polyhedron(rays=[self[j] for j in zero_indices], backend=self._backend) the_verts = tuple([ _ for _ in zero_indices if not the_cone.relative_interior_contains(self[_]) ]) assert len(the_verts) == 2, "problem with the cocircuits" if the_verts not in list_verts: list_verts += [the_verts] return list_verts
def is_union_convex(t): r""" Return whether the union of the polyhedrons is convex. INPUT: - ``t`` -- list of polyhedron EXAMPLES:: sage: from slabbe.polyhedron_partition import is_union_convex sage: h = 1/2 sage: p = Polyhedron([(0,h),(0,1),(h,1)]) sage: q = Polyhedron([(0,0), (0,h), (h,1), (1,1), (1,h), (h,0)]) sage: r = Polyhedron([(h,0), (1,0), (1,h)]) sage: is_union_convex((p,q,r)) True sage: is_union_convex((p,q)) True sage: is_union_convex((p,r)) False Here we need to consider the three at the same time to get a convex union:: sage: h = 1/5 sage: p = Polyhedron([(0,0),(h,1-h),(0,1)]) sage: q = Polyhedron([(0,1), (h,1-h), (1,1)]) sage: r = Polyhedron([(0,0), (h,1-h), (1,1), (1,0)]) sage: is_union_convex((p,q)) False sage: is_union_convex((p,r)) False sage: is_union_convex((q,r)) False sage: is_union_convex((p,q,r)) True """ if not t: return True base_ring = t[0].base_ring() vertices = sum((p.vertices() for p in t), tuple()) r = Polyhedron(vertices, base_ring=base_ring) return r.volume() == sum(p.volume() for p in t)
def deformation_cone(v): r""" Return the deformation cone of the given vector ``v`` EXAMPLES:: sage: from surface_dynamics.misc.linalg import deformation_cone sage: K.<sqrt2> = QuadraticField(2) sage: v3 = vector([sqrt2, 1, 1+sqrt2]) sage: P = deformation_cone(v3) sage: P A 2-dimensional polyhedron in QQ^3 defined as the convex hull of 1 vertex and 2 rays sage: P.rays_list() [[1, 0, 1], [0, 1, 1]] """ V = deformation_space(v) P = Polyhedron(lines=deformation_space(v).basis()) B = Polyhedron(rays=(QQ**V.degree()).basis()) return P.intersection(B)
def _an_element_(self): """ Returns a Newton polygon (which is the empty one) TESTS: sage: from sage.geometry.newton_polygon import NewtonPolygon sage: NewtonPolygon._an_element_() Empty Newton polygon """ return self(Polyhedron(base_ring=self.base_ring(), ambient_dim=2))
def _borcherds_product_polyhedron(self, pole_order, prec, verbose=False): r""" Construct a polyhedron representing a cone of Heegner divisors. For internal use in the methods borcherds_input_basis() and borcherds_input_Qbasis(). INPUT: - ``pole_order`` -- pole order - ``prec`` -- precision OUTPUT: a tuple consisting of an integral matrix M, a Polyhedron p, and a WeilRepModularFormsBasis X EXAMPLES:: sage: from weilrep import * sage: m = ParamodularForms(5) sage: m._borcherds_product_polyhedron(1/4, 5)[1] A 2-dimensional polyhedron in QQ^3 defined as the convex hull of 1 vertex and 2 rays """ S = self.gram_matrix() wt = self.input_wt() w = self.weilrep() rds = w.rds() norm_dict = w.norm_dict() X = w.nearly_holomorphic_modular_forms_basis(wt, pole_order, prec, verbose=verbose) N = len([g for g in rds if not norm_dict[tuple(g)]]) v_list = w.coefficient_vector_exponents(0, 1, starting_from=-pole_order, include_vectors=True) exp_list = [v[1] for v in v_list] v_list = [vector(v[0]) for v in v_list] positive = [None] * len(exp_list) zero = vector([0] * (len(exp_list) + 1)) M = matrix([ x.coefficient_vector(starting_from=-pole_order, ending_with=0)[:-N] for x in X ]) vs = M.transpose().kernel().basis() for i, n in enumerate(exp_list): ieq = copy(zero) ieq[i + 1] = 1 for j, m in enumerate(exp_list[:i]): N = sqrt(m / n) if N in ZZ: v1 = v_list[i] v2 = v_list[j] ieq[j + 1] = denominator(v1 * N - v2) == 1 or denominator(v1 * N + v2) == 1 positive[i] = ieq p = Polyhedron(ieqs=positive, eqns=[vector([0] + list(v)) for v in vs]) return M, p, X
def deformation_cone(v): r""" Return the deformation cone of the given vector ``v`` EXAMPLES:: sage: from surface_dynamics.misc.linalg import deformation_cone sage: K.<sqrt2> = QuadraticField(2) sage: v3 = vector([sqrt2, 1, 1+sqrt2]) sage: P = deformation_cone(v3) sage: P A 2-dimensional polyhedron in QQ^3 defined as the convex hull of 1 vertex and 2 rays sage: P.rays_list() [[1, 0, 1], [0, 1, 1]] """ from sage.rings.all import QQ from sage.geometry.polyhedron.constructor import Polyhedron V = deformation_space(v) P = Polyhedron(lines=deformation_space(v).basis()) B = Polyhedron(rays=(QQ**V.degree()).basis()) return P.intersection(B)
def verify(self, vertices, rays, lines): """ Compare result to PPL if the base ring is QQ. This method is for debugging purposes and compares the computation with another backend if available. INPUT: - ``vertices``, ``rays``, ``lines`` -- see :class:`Vrep2Hrep`. EXAMPLES:: sage: from sage.geometry.polyhedron.double_description_inhomogeneous import Vrep2Hrep sage: vertices = [(-1/2,0)] sage: rays = [(-1/2,2/3), (1/2,-1/3)] sage: lines = [] sage: V2H = Vrep2Hrep(QQ, 2, vertices, rays, lines) sage: V2H.verify(vertices, rays, lines) """ from sage.rings.all import QQ from sage.geometry.polyhedron.constructor import Polyhedron if self.base_ring is not QQ: return P = Polyhedron(vertices=vertices, rays=rays, lines=lines, base_ring=QQ, ambient_dim=self.dim) trivial = [self.base_ring.one()] + [self.base_ring.zero()] * self.dim # always true equation Q = Polyhedron(ieqs=self.inequalities + [trivial], eqns=self.equations, base_ring=QQ, ambient_dim=self.dim) if not P == Q: print 'incorrect!', P, Q print Q.Vrepresentation() print P.Hrepresentation()
def experiment(): rank = 5 level = 4 num_points = 11 client = cbc.CBClient() liealg = cbd.TypeALieAlgebra(rank, store_fusion=True, exact=True) rays = [] wts = [] ranks = [] for wt in liealg.get_weights(level): if wt == tuple([0 for x in range(0, rank)]): continue cbb = cbd.SymmetricConformalBlocksBundle(client, liealg, wt, num_points, level) if cbb.get_rank() == 0: continue divisor = cbb.get_symmetrized_divisor() if divisor == [ sage.Rational(0) for x in range(0, num_points // 2 - 1) ]: continue rays = rays + [divisor] wts = wts + [wt] ranks = ranks + [cbb.get_rank()] #print(wt, cbb.get_rank(), divisor) p = Polyhedron(rays=rays, base_ring=RationalField(), backend="cdd") extremal_rays = [list(v.vector()) for v in p.Vrepresentation()] c = Cone(p) print("Extremal rays:") for i in range(0, len(rays)): ray = rays[i] wt = wts[i] rk = ranks[i] if ray in extremal_rays: print(rk, wt, ray)
def platonic_tetrahedron(): r"""Produce a triple consisting of a polyhedral version of the platonic tetrahedron, the associated cone surface, and a ConeSurfaceToPolyhedronMap from the surface to the polyhedron. EXAMPLES:: sage: from flatsurf.geometry.polyhedra import platonic_tetrahedron sage: polyhedron,surface,surface_to_polyhedron = platonic_tetrahedron() sage: TestSuite(surface).run() r""" vertices = [] for x in range(-1, 3, 2): for y in range(-1, 3, 2): vertices.append(vector(QQ, (x, y, x * y))) p = Polyhedron(vertices=vertices) s, m = polyhedron_to_cone_surface(p, scaling_factor=AA(1 / sqrt(2))) return p, s, m
def random_interior_point_compact_polytope(self, uniform='simplex', integer=False): r""" Return a random interior point of a compact polytope. INPUT: - ``uniform`` -- ``'points'`` (slow) or ``'simplex'`` (fast), whether to take the probability uniformly with respect to the set of integral points or with respect to the simplexes. - ``integer`` -- bool, whether the output must be with integer coordinates EXEMPLES:: sage: from slabbe.combinat import random_interior_point_compact_polytope sage: p = polytopes.hypercube(3) sage: p = p + vector([30,20,10]) sage: p.center() (30, 20, 10) sage: random_interior_point_compact_polytope(p) # random (19.33174562788114, -0.5428002756082744, -0.3568284089832092) sage: random_interior_point_compact_polytope(p) # random (20.039169786976075, -0.4121594862234468, -0.05623023234688396) sage: random_interior_point_compact_polytope(p, integer=True) # random (30, 19, 9) """ assert self.is_compact(), "input is not compact" from sage.geometry.polyhedron.constructor import Polyhedron triangulation = self.triangulate() T = [] for simplex_indices in self.triangulate(): simplex_vertices = [self.Vrepresentation(i) for i in simplex_indices] simplex = Polyhedron(simplex_vertices) T.append(simplex) if uniform == 'points': v = [p.integral_points_count() for p in T] # slow i = non_uniform_randint(v) elif uniform == 'simplex': i = randrange(len(T)) else: raise ValueError('unknown value for uniform(={})'.format(uniform)) return random_interior_point_simplex(T[i], integer=integer)
def permutahedron(self, point=None): r""" Return the permutahedron of ``self``. This is the convex hull of the point ``point`` in the weight basis under the action of ``self`` on the underlying vector space `V`. INPUT: - ``point`` -- optional, a point given by its coordinates in the weight basis (default is `(1, 1, 1, \ldots)`) .. NOTE:: The result is expressed in the root basis coordinates. EXAMPLES:: sage: W = ReflectionGroup(['A',3]) # optional - gap3 sage: W.permutahedron() # optional - gap3 A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 24 vertices sage: W = ReflectionGroup(['A',3],['B',2]) # optional - gap3 sage: W.permutahedron() # optional - gap3 A 5-dimensional polyhedron in QQ^5 defined as the convex hull of 192 vertices TESTS:: sage: W = ReflectionGroup(['A',3]) # optional - gap3 sage: W.permutahedron([3,5,8]) # optional - gap3 A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 24 vertices """ n = self.rank() weights = self.fundamental_weights() if point is None: point = [1] * n v = sum(point[i] * wt for i, wt in enumerate(weights)) from sage.geometry.polyhedron.constructor import Polyhedron return Polyhedron(vertices=[v*w.to_matrix() for w in self])
def platonic_octahedron(): r"""Produce a triple consisting of a polyhedral version of the platonic octahedron, the associated cone surface, and a ConeSurfaceToPolyhedronMap from the surface to the polyhedron. EXAMPLES:: sage: from flatsurf.geometry.polyhedra import platonic_octahedron sage: polyhedron,surface,surface_to_polyhedron = platonic_octahedron() sage: TestSuite(surface).run() r""" vertices = [] for i in range(3): temp = vector(QQ, [1 if k == i else 0 for k in range(3)]) for j in range(-1, 3, 2): vertices.append(j * temp) octahedron = Polyhedron(vertices=vertices) surface,surface_to_octahedron = \ polyhedron_to_cone_surface(octahedron,scaling_factor=AA(sqrt(2))) return octahedron, surface, surface_to_octahedron
def plot_walls(self, walls): r""" Plot ``walls``, i.e. 2-d cones, and their labels. Ray generators must be specified during construction or using :meth:`set_rays` before calling this method and these specified ray generators will be used in conjunction with :meth:`~sage.geometry.cone.ConvexRationalPolyhedralCone.ambient_ray_indices` of ``walls``. INPUT: - ``walls`` -- a list of 2-d cones. OUTPUT: - a plot. EXAMPLES:: sage: quadrant = Cone([(1,0), (0,1)]) sage: from sage.geometry.toric_plotter import ToricPlotter sage: tp = ToricPlotter(dict(), 2, quadrant.rays()) sage: tp.plot_walls([quadrant]) Graphics object consisting of 2 graphics primitives Let's also check that the truncating polyhedron is functioning correctly:: sage: tp = ToricPlotter({"mode": "box"}, 2, quadrant.rays()) sage: tp.plot_walls([quadrant]) Graphics object consisting of 2 graphics primitives """ result = Graphics() if not walls or not self.show_walls: return result rays = self.rays extra_options = self.extra_options mode = self.mode alpha = self.wall_alpha colors = color_list(self.wall_color, len(walls)) zorder = self.wall_zorder if mode == "box": if self.dimension <= 2: ieqs = [(self.xmax, -1, 0), (- self.xmin, 1, 0), (self.ymax, 0, -1), (- self.ymin, 0, 1)] else: ieqs = [(self.xmax, -1, 0, 0), (- self.xmin, 1, 0, 0), (self.ymax, 0, -1, 0), (- self.ymin, 0, 1, 0), (self.zmax, 0, 0, -1), (- self.zmin, 0, 0, 1)] box = Polyhedron(ieqs=ieqs, base_ring=RDF) for wall, color in zip(walls, colors): result += box.intersection(wall.polyhedron()).render_solid( alpha=alpha, color=color, zorder=zorder, **extra_options) elif mode == "generators": origin = self.origin for wall, color in zip(walls, colors): vertices = [rays[i] for i in wall.ambient_ray_indices()] vertices.append(origin) result += Polyhedron(vertices=vertices, base_ring=RDF).render_solid( alpha=alpha, color=color, zorder=zorder, **extra_options) label_sectors = [] round = mode == "round" for wall, color in zip(walls, colors): S = wall.linear_subspace() lsd = S.dimension() if lsd == 0: # Strictly convex wall r1, r2 = (rays[i] for i in wall.ambient_ray_indices()) elif lsd == 1: # wall is a half-plane for i, ray in zip(wall.ambient_ray_indices(), wall.rays()): if ray in S: r1 = rays[i] else: r2 = rays[i] if round: # Plot one "extra" sector result += sector(- r1, r2, alpha=alpha, color=color, zorder=zorder, **extra_options) else: # wall is a plane r1, r2 = S.basis() r1 = vector(RDF, r1) r1 = r1 / r1.norm() * self.radius r2 = vector(RDF, r2) r2 = r2 / r2.norm() * self.radius if round: # Plot three "extra" sectors result += sector(r1, - r2, alpha=alpha, color=color, zorder=zorder, **extra_options) result += sector(- r1, r2, alpha=alpha, color=color, zorder=zorder, **extra_options) result += sector(- r1, - r2, alpha=alpha, color=color, zorder=zorder, **extra_options) label_sectors.append([r1, r2]) if round: result += sector(r1, r2, alpha=alpha, color=color, zorder=zorder, **extra_options) result += self.plot_labels(self.wall_label, [sum(label_sector) / 3 for label_sector in label_sectors]) return result
def RandomTriangulation(n, embed=False, base_ring=QQ): """ Returns a random triangulation on n vertices. A triangulation is a planar graph all of whose faces are triangles (3-cycles). The graph is built by independently generating `n` points uniformly at random on the surface of a sphere, finding the convex hull of those points, and then returning the 1-skeleton of that polyhedron. INPUT: - ``n`` -- number of vertices (recommend `n \ge 3`) - ``embed`` -- (optional, default ``False``) whether to use the stereographic point projections to draw the graph. - ``base_ring`` -- (optional, default ``QQ``) specifies the field over which to do the intermediate computations. The default setting is slower, but works for any input; one can instead use ``RDF``, but this occasionally fails due to loss of precision, as mentioned on :trac:10276. EXAMPLES:: sage: g = graphs.RandomTriangulation(10) sage: g.is_planar() True sage: g.num_edges() == 3*g.order() - 6 True TESTS:: sage: for i in range(10): ....: g = graphs.RandomTriangulation(30,embed=True) ....: assert g.is_planar() and g.size() == 3*g.order()-6 """ from sage.misc.prandom import normalvariate from sage.geometry.polyhedron.constructor import Polyhedron from sage.rings.real_double import RDF # this function creates a random unit vector in R^3 def rand_unit_vec(): vec = [normalvariate(0, 1) for k in range(3)] mag = sum([x * x for x in vec]) ** 0.5 return [x / mag for x in vec] # generate n unit vectors at random points = [rand_unit_vec() for k in range(n)] # find their convex hull P = Polyhedron(vertices=points, base_ring=base_ring) # extract the 1-skeleton g = P.vertex_graph() g.rename('Planar triangulation on {} vertices'.format(n)) if embed: from sage.geometry.polyhedron.plot import ProjectionFuncStereographic from sage.modules.free_module_element import vector proj = ProjectionFuncStereographic([0, 0, 1]) ppoints = [proj(vector(x)) for x in points] g.set_pos({i: ppoints[i] for i in range(len(points))}) return g
def induced_out_partition(self, trans, ieq): r""" Returns the output partition obtained as the induction of the given transformation on the domain given by an inequality. Note: the output partition corresponds to the arrival partition in the domain, not the initial one. INPUT: - ``trans`` -- a function: polyhedron -> polyhedron - ``ieq`` -- list, an inequality. An entry equal to "[-1,7,3,4]" represents the inequality 7x_1+3x_2+4x_3>= 1. OUTPUT: dict of polyhedron partitions with keys giving the return time EXAMPLES:: sage: from slabbe import PolyhedronPartition, rotation_mod sage: h = 1/3 sage: p = Polyhedron([(0,h),(0,1),(h,1)]) sage: q = Polyhedron([(0,0), (0,h), (h,1), (h,0)]) sage: r = Polyhedron([(h,1), (1,1), (1,h), (h,0)]) sage: s = Polyhedron([(h,0), (1,0), (1,h)]) sage: P = PolyhedronPartition({0:p, 1:q, 2:r, 3:s}) sage: u = rotation_mod(0, 1/3, 1, QQ) sage: ieq = [h, -1, 0] # x0 <= h sage: P.induced_out_partition(u, ieq) {3: Polyhedron partition of 4 atoms with 4 letters} :: sage: P = PolyhedronPartition({0:p, 1:q, 2:r, 3:s}) sage: ieq2 = [1/2, -1, 0] # x0 <= 1/2 sage: d = P.induced_out_partition(u, ieq2) sage: d {1: Polyhedron partition of 2 atoms with 2 letters, 2: Polyhedron partition of 3 atoms with 3 letters, 3: Polyhedron partition of 4 atoms with 4 letters} sage: Q = PolyhedronPartition(d[1].atoms()+d[2].atoms()+d[3].atoms()) sage: Q.is_pairwise_disjoint() True :: sage: P = PolyhedronPartition({0:p, 1:q, 2:r, 3:s}) sage: ieq3 = [-1/2, 1, 0] # x0 >= 1/2 sage: P.induced_out_partition(u, ieq3) {2: Polyhedron partition of 3 atoms with 3 letters, 3: Polyhedron partition of 4 atoms with 4 letters} It is an error if the induced region is empty:: sage: P = PolyhedronPartition({0:p, 1:q, 2:r, 3:s}) sage: ieq4 = [-1/2, -1, 0] # x0 <= -1/2 sage: P.induced_out_partition(u, ieq4) Traceback (most recent call last): ... ValueError: Inequality An inequality (-2, 0) x - 1 >= 0 does not intersect P (=Polyhedron partition of 4 atoms with 4 letters) The whole domain:: sage: P = PolyhedronPartition({0:p, 1:q, 2:r, 3:s}) sage: ieq5 = [1/2, 1, 0] # x0 >= -1/2 sage: P.induced_out_partition(u, ieq5) {1: Polyhedron partition of 4 atoms with 4 letters} An irrational rotation:: sage: z = polygen(QQ, 'z') #z = QQ['z'].0 # same as sage: K = NumberField(z**2-z-1, 'phi', embedding=RR(1.6)) sage: phi = K.gen() sage: h = 1/phi^2 sage: p = Polyhedron([(0,h),(0,1),(h,1)]) sage: q = Polyhedron([(0,0), (0,h), (h,1), (h,0)]) sage: r = Polyhedron([(h,1), (1,1), (1,h), (h,0)]) sage: s = Polyhedron([(h,0), (1,0), (1,h)]) sage: P = PolyhedronPartition({0:p, 1:q, 2:r, 3:s}, base_ring=K) sage: u = rotation_mod(0, 1/phi, 1, K) sage: ieq = [phi^-4, -1, 0] # x0 <= phi^-4 sage: d = P.induced_out_partition(u, ieq) sage: d {5: Polyhedron partition of 6 atoms with 6 letters, 8: Polyhedron partition of 9 atoms with 9 letters} """ # good side of the hyperplane half = Polyhedron(ieqs=[ieq]) half_part = PolyhedronPartition([half]) # the other side of the hyperplane other_half = Polyhedron(ieqs=[[-a for a in ieq]]) other_half_part = PolyhedronPartition([other_half]) # initial refinement P = self.refinement(half_part) if len(P) == 0: raise ValueError("Inequality {} does not intersect P " "(={})".format(half.inequalities()[0], self)) level = 1 ans = {} P = P.apply_transformation(trans) while len(P): P_returned = P.refinement(half_part) if P_returned: ans[level] = P_returned # for what is remaining we do: P = P.refinement(other_half_part) P = P.refinement(self) P = P.apply_transformation(trans) level += 1 return ans