Commits (24)
......@@ -2642,6 +2642,11 @@ REFERENCES:
algebra of type* `A`. Proc. Amer. Math. Soc. **138** (2010), no. 11,
3877--3889.
.. [KS2019] \J. Kliem and C. Stump.
*A face iterator for polyhedra and more general finite locally
branched lattices*.
Preprint (2019): :arxiv:`1905.01945`.
.. [KSV2011] Ian Kiming, Matthias Schuett and Helena Verrill, "Lifts
of projective congruence groups", J. London
Math. Soc. (2011) 83 (1): 96-120,
......
......@@ -293,6 +293,27 @@ ext_modules = [
'sage/geometry/triangulation/triangulations.h'],
language="c++"),
Extension('sage.geometry.polyhedron.combinatorial_polyhedron.base',
sources = ['sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx']),
Extension('sage.geometry.polyhedron.combinatorial_polyhedron.list_of_faces',
sources = ['sage/geometry/polyhedron/combinatorial_polyhedron/list_of_faces.pyx']),
Extension('sage.geometry.polyhedron.combinatorial_polyhedron.bit_vector_operations.cc',
sources = ['sage/geometry/polyhedron/combinatorial_polyhedron/bit_vector_operations.cc']),
Extension('sage.geometry.polyhedron.combinatorial_polyhedron.face_iterator',
sources = ['sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pyx']),
Extension('sage.geometry.polyhedron.combinatorial_polyhedron.polyhedron_face_lattice',
sources = ['sage/geometry/polyhedron/combinatorial_polyhedron/polyhedron_face_lattice.pyx']),
Extension('sage.geometry.polyhedron.combinatorial_polyhedron.combinatorial_face',
sources = ['sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face.pyx']),
Extension('sage.geometry.polyhedron.combinatorial_polyhedron.conversions',
sources = ['sage/geometry/polyhedron/combinatorial_polyhedron/conversions.pyx']),
################################
##
## sage.graphs
......
......@@ -2,4 +2,4 @@
from sage.misc.lazy_import import lazy_import
lazy_import('sage.geometry.polyhedron.constructor', 'Polyhedron')
lazy_import('sage.geometry.polyhedron.library', 'polytopes')
lazy_import('sage.geometry.polyhedron.combinatorial_polyhedron.base' , 'CombinatorialPolyhedron')
......@@ -21,7 +21,7 @@ import six
from sage.structure.element import Element, coerce_binop, is_Vector
from sage.structure.richcmp import rich_to_bool, op_NE
from sage.misc.all import cached_method, prod
from sage.misc.all import cached_method, prod, lazy_import
from sage.misc.randstate import current_randstate
from sage.rings.all import QQ, ZZ, AA
......@@ -33,6 +33,8 @@ from sage.functions.other import sqrt, floor, ceil, binomial
from sage.groups.matrix_gps.finitely_generated import MatrixGroup
from sage.graphs.graph import Graph
from sage.graphs.digraph import DiGraph
lazy_import('sage.geometry.polyhedron.face' , 'combinatorial_face_to_polyhedral_face')
lazy_import('sage.geometry.polyhedron.face' , 'PolyhedronFace')
from .constructor import Polyhedron
......@@ -296,8 +298,6 @@ class Polyhedron_base(Element):
[1 1 0]
"""
# TODO: This implementation computes the whole face lattice,
# which is much more information than necessary.
M = matrix(ZZ, self.n_facets(), self.n_facets(), 0)
codim = self.ambient_dim()-self.dim()
......@@ -3828,13 +3828,13 @@ class Polyhedron_base(Element):
sage: vertex_trunc1.f_vector()
(1, 10, 15, 7, 1)
sage: tuple(f.ambient_V_indices() for f in vertex_trunc1.faces(2))
((0, 1, 2, 3),
(2, 3, 4, 5),
(1, 2, 5, 6),
((4, 5, 6, 7, 9),
(0, 3, 4, 8, 9),
(0, 1, 6, 7, 8),
(4, 5, 6, 7, 9),
(7, 8, 9),
(0, 3, 4, 8, 9))
(2, 3, 4, 5),
(1, 2, 5, 6),
(0, 1, 2, 3))
sage: vertex_trunc1.vertices()
(A vertex at (1, -1, -1),
A vertex at (1, 1, -1),
......@@ -3850,13 +3850,13 @@ class Polyhedron_base(Element):
sage: vertex_trunc2.f_vector()
(1, 10, 15, 7, 1)
sage: tuple(f.ambient_V_indices() for f in vertex_trunc2.faces(2))
((0, 1, 2, 3),
(2, 3, 4, 5),
(1, 2, 5, 6),
((4, 5, 6, 7, 9),
(0, 3, 4, 8, 9),
(0, 1, 6, 7, 8),
(4, 5, 6, 7, 9),
(7, 8, 9),
(0, 3, 4, 8, 9))
(2, 3, 4, 5),
(1, 2, 5, 6),
(0, 1, 2, 3))
sage: vertex_trunc2.vertices()
(A vertex at (1, -1, -1),
A vertex at (1, 1, -1),
......@@ -3880,18 +3880,18 @@ class Polyhedron_base(Element):
A vertex at (-0.4, -1.0, -1.0),
A vertex at (-1.0, -0.4, -1.0),
A vertex at (-1.0, -1.0, -0.4))
sage: edge_trunc = Cube.face_truncation(Cube.faces(1)[0])
sage: edge_trunc = Cube.face_truncation(Cube.faces(1)[1])
sage: edge_trunc.f_vector()
(1, 10, 15, 7, 1)
sage: tuple(f.ambient_V_indices() for f in edge_trunc.faces(2))
((0, 1, 2, 3),
(1, 2, 4, 5),
(4, 5, 6, 7),
((4, 5, 6, 7),
(0, 3, 8, 9),
(0, 1, 5, 6, 8),
(2, 3, 4, 7, 9),
(6, 7, 8, 9),
(0, 3, 8, 9))
sage: face_trunc = Cube.face_truncation(Cube.faces(2)[0])
(2, 3, 4, 7, 9),
(1, 2, 4, 5),
(0, 1, 2, 3))
sage: face_trunc = Cube.face_truncation(Cube.faces(2)[2])
sage: face_trunc.vertices()
(A vertex at (1, -1, -1),
A vertex at (1, 1, -1),
......@@ -4000,17 +4000,17 @@ class Polyhedron_base(Element):
sage: Q = Polyhedron(vertices=[[0,1],[1,0]],rays=[[1,1]])
sage: E = Q.faces(1)
sage: Q.stack(E[0],1/2).Vrepresentation()
sage: Q.stack(E[1],1/2).Vrepresentation()
(A vertex at (0, 1),
A vertex at (0, 2),
A vertex at (1, 0),
A ray in the direction (1, 1))
sage: Q.stack(E[1],1/2).Vrepresentation()
sage: Q.stack(E[2],1/2).Vrepresentation()
(A vertex at (0, 0),
A vertex at (0, 1),
A vertex at (1, 0),
A ray in the direction (1, 1))
sage: Q.stack(E[2],1/2).Vrepresentation()
sage: Q.stack(E[0],1/2).Vrepresentation()
(A vertex at (0, 1),
A vertex at (1, 0),
A ray in the direction (1, 1),
......@@ -4335,7 +4335,12 @@ class Polyhedron_base(Element):
return PolyhedronFace(self, Vindices, Hindices)
@cached_method
def face_lattice(self):
def combinatorial_polyhedron(self):
from sage.geometry.polyhedron.combinatorial_polyhedron.base import CombinatorialPolyhedron
return CombinatorialPolyhedron(self)
@cached_method
def face_lattice(self, labels=True):
"""
Return the face-lattice poset.
......@@ -4398,10 +4403,10 @@ class Polyhedron_base(Element):
sage: square = polytopes.hypercube(2)
sage: fl = square.face_lattice();fl
Finite lattice containing 10 elements with distinguished linear extension
sage: list(f.ambient_V_indices() for f in fl)
[(), (0,), (1,), (2,), (3,), (0, 1), (0, 2), (2, 3), (1, 3), (0, 1, 2, 3)]
sage: poset_element = fl[6]
Finite lattice containing 10 elements
sage: sorted(list(f.ambient_V_indices() for f in fl))
[(), (0,), (0, 1), (0, 1, 2, 3), (0, 2), (1,), (1, 3), (2,), (2, 3), (3,)]
sage: poset_element = sorted(fl)[4]
sage: a_face = poset_element
sage: a_face
A 1-dimensional face of a Polyhedron in ZZ^2 defined as the convex hull of 2 vertices
......@@ -4468,39 +4473,21 @@ class Polyhedron_base(Element):
sage: [[ls.ambient_V_indices() for ls in lss] for lss in Polyhedron(lines=[(1,0)], vertices=[(0,0)]).face_lattice().level_sets()]
[[()], [(0, 1)]]
"""
coatom_to_Hindex = [ h.index() for h in self.inequality_generator() ]
Hindex_to_coatom = [None] * self.n_Hrepresentation()
for i in range(len(coatom_to_Hindex)):
Hindex_to_coatom[ coatom_to_Hindex[i] ] = i
atom_to_Vindex = [ v.index() for v in self.Vrep_generator() if not v.is_line() ]
Vindex_to_atom = [None] * self.n_Vrepresentation()
for i in range(len(atom_to_Vindex)):
Vindex_to_atom[ atom_to_Vindex[i] ] = i
atoms_incidences = [ tuple([ Hindex_to_coatom[h.index()]
for h in v.incident() if h.is_inequality() ])
for v in self.Vrepresentation() if not v.is_line() ]
coatoms_incidences = [ tuple([ Vindex_to_atom[v.index()]
for v in h.incident() if not v.is_line() ])
for h in self.Hrepresentation() if h.is_inequality() ]
unlabeled = self.combinatorial_polyhedron().face_lattice()
if labels:
combinatorial_face_meth = self.combinatorial_polyhedron().face_by_face_lattice_index
atoms_vertices = [ Vindex_to_atom[v.index()] for v in self.vertex_generator() ]
equations = [ e.index() for e in self.equation_generator() ]
lines = [ l.index() for l in self.line_generator() ]
def label_func(i):
return combinatorial_face_to_polyhedral_face(self, combinatorial_face_meth(i))
def face_constructor(atoms, coatoms):
if len(atoms) == 0:
Vindices = ()
else:
Vindices = tuple(sorted([ atom_to_Vindex[i] for i in atoms ]+lines))
Hindices = tuple(sorted([ coatom_to_Hindex[i] for i in coatoms ]+equations))
return self._make_polyhedron_face(Vindices, Hindices)
return unlabeled.relabel(label_func)
else:
return unlabeled
from sage.geometry.hasse_diagram import lattice_from_incidences
return lattice_from_incidences(atoms_incidences, coatoms_incidences,
face_constructor=face_constructor, required_atoms=atoms_vertices)
def face_iter(self, dimension=None, dual=None):
it = self.combinatorial_polyhedron().face_iter(dimension=dimension, dual=dual)
for face in it:
yield combinatorial_face_to_polyhedral_face(self, face)
def faces(self, face_dimension):
"""
......@@ -4525,16 +4512,16 @@ class Polyhedron_base(Element):
sage: p = polytopes.hypercube(4)
sage: list(f.ambient_V_indices() for f in p.faces(3))
[(0, 1, 2, 3, 4, 5, 6, 7),
(0, 1, 2, 3, 8, 9, 10, 11),
[(0, 2, 4, 6, 8, 10, 12, 14),
(0, 1, 4, 5, 8, 9, 12, 13),
(0, 2, 4, 6, 8, 10, 12, 14),
(0, 1, 2, 3, 8, 9, 10, 11),
(0, 1, 2, 3, 4, 5, 6, 7),
(1, 3, 5, 7, 9, 11, 13, 15),
(2, 3, 6, 7, 10, 11, 14, 15),
(8, 9, 10, 11, 12, 13, 14, 15),
(4, 5, 6, 7, 12, 13, 14, 15),
(1, 3, 5, 7, 9, 11, 13, 15)]
(8, 9, 10, 11, 12, 13, 14, 15)]
sage: face = p.faces(3)[0]
sage: face = p.faces(3)[3]
sage: face.ambient_Hrepresentation()
(An inequality (1, 0, 0, 0) x + 1 >= 0,)
sage: face.vertices()
......@@ -4556,6 +4543,15 @@ class Polyhedron_base(Element):
sage: [ ([get_idx(_) for _ in face.ambient_Vrepresentation()],
....: [get_idx(_) for _ in face.ambient_Hrepresentation()])
....: for face in p.faces(3) ]
[([0, 2, 4, 6, 8, 10, 12, 14], [7]),
([0, 1, 4, 5, 8, 9, 12, 13], [6]),
([0, 1, 2, 3, 8, 9, 10, 11], [5]),
([0, 1, 2, 3, 4, 5, 6, 7], [4]),
([1, 3, 5, 7, 9, 11, 13, 15], [3]),
([2, 3, 6, 7, 10, 11, 14, 15], [2]),
([4, 5, 6, 7, 12, 13, 14, 15], [1]),
([8, 9, 10, 11, 12, 13, 14, 15], [0])]
[([0, 1, 2, 3, 4, 5, 6, 7], [4]),
([0, 1, 2, 3, 8, 9, 10, 11], [5]),
([0, 1, 4, 5, 8, 9, 12, 13], [6]),
......@@ -4579,14 +4575,16 @@ class Polyhedron_base(Element):
sage: pr.faces(0)
()
sage: pr.faces(-1)
()
"""
fl = self.face_lattice().level_sets()
codim = self.dim() - face_dimension
index = len(fl) - 1 - codim
if index >= len(fl) or index < 1:
return tuple()
return tuple(fl[index])
(A -1-dimensional face of a Polyhedron in QQ^3,)
"""
if face_dimension in range(self.dimension()):
return tuple(self.face_iter(face_dimension))
elif face_dimension == -1:
return (PolyhedronFace(self, (), range(self.n_Hrepresentation())),)
elif face_dimension == self.dimension():
return (PolyhedronFace(self, range(self.n_Vrepresentation()), range(self.n_equations())),)
else:
return ()
@cached_method
def f_vector(self):
......@@ -4605,7 +4603,21 @@ class Polyhedron_base(Element):
sage: p.f_vector()
(1, 7, 12, 7, 1)
"""
return vector(ZZ, [len(x) for x in self.face_lattice().level_sets()])
return vector(ZZ, self.combinatorial_polyhedron().f_vector())
def _vertex_graph_edges(self):
if self.is_compact():
return self.combinatorial_polyhedron().edges()
elif self.n_lines() == 0:
edges = self.combinatorial_polyhedron().edges()
edges_with_vertices = tuple(x for x in edges
if x[0].is_vertex() and x[1].is_vertex())
return edges_with_vertices
else:
n_lines = self.n_lines()
edges = tuple(x.vertices() for x in self.faces(n_lines + 1))
edges_with_vertices = tuple(x for x in edges if len(x) == 2)
return edges_with_vertices
def vertex_graph(self):
"""
......@@ -4623,36 +4635,12 @@ class Polyhedron_base(Element):
sage: s4.is_eulerian()
True
"""
from itertools import combinations
inequalities = self.inequalities()
vertices = self.vertices()
# Associated to 'v' the inequalities in contact with v
vertex_ineq_incidence = [frozenset([i for i, ineq in enumerate(inequalities) if self._is_zero(ineq.eval(v))])
for i, v in enumerate(vertices)]
# the dual incidence structure
ineq_vertex_incidence = [set() for _ in range(len(inequalities))]
for v, ineq_list in enumerate(vertex_ineq_incidence):
for ineq in ineq_list:
ineq_vertex_incidence[ineq].add(v)
n = len(vertices)
pairs = []
for i, j in combinations(range(n), 2):
common_ineq = vertex_ineq_incidence[i] & vertex_ineq_incidence[j]
if not common_ineq: # or len(common_ineq) < d-2:
continue
if len(set.intersection(*[ineq_vertex_incidence[k] for k in common_ineq])) == 2:
pairs.append((i, j))
from sage.graphs.graph import Graph
g = Graph()
g.add_vertices(vertices)
g.add_edges((vertices[i], vertices[j]) for i, j in pairs)
return g
if self.n_vertices() == 1:
G = Graph()
G.add_vertices(self.vertices())
return G
edges = self._vertex_graph_edges()
return Graph(data=edges, format='list_of_edges')
graph = vertex_graph
......@@ -4719,11 +4707,16 @@ class Polyhedron_base(Element):
f = -f
from sage.graphs.digraph import DiGraph
dg = DiGraph()
for j in range(self.n_vertices()):
vj = self.Vrepresentation(j)
for vi in vj.neighbors():
if orientation_check(vj.vector() - vi.vector()):
dg.add_edge(vi, vj)
if self.n_vertices() == 1:
dg.add_vertices(self.vertices())
return dg
edges = self._vertex_graph_edges()
for edge in edges:
if orientation_check(edge[1].vector() - edge[0].vector()):
dg.add_edge(edge[0], edge[1])
if orientation_check(edge[0].vector() - edge[1].vector()):
dg.add_edge(edge[1], edge[0])
return dg
def polar(self):
......@@ -5280,7 +5273,7 @@ class Polyhedron_base(Element):
A 2-dimensional polyhedron in AA^2 defined as the convex hull of 6 vertices
sage: edge = S.faces(1)[2].as_polyhedron()
sage: edge.vertices()
(A vertex at (0.866025403784439?, 1/2), A vertex at (0, 1))
(A vertex at (0, -1), A vertex at (-0.866025403784439?, -1/2))
sage: edge.volume()
0
sage: edge.volume(measure='induced')
......@@ -5796,7 +5789,8 @@ class Polyhedron_base(Element):
return self.dim() + 1
else:
k = 1
while len(self.faces(k)) == binomial(self.n_vertices(), k + 1):
f_vector = self.f_vector()
while f_vector[k+1] == binomial(self.n_vertices(), k + 1):
k += 1
return k
......@@ -5849,7 +5843,8 @@ class Polyhedron_base(Element):
"""
if k is None:
k = self.dim() // 2
return all(len(self.faces(i)) == binomial(self.n_vertices(), i + 1)
f_vector = self.f_vector()
return all(f_vector[i+1] == binomial(self.n_vertices(), i + 1)
for i in range(1, k))
@cached_method
......@@ -6931,7 +6926,7 @@ class Polyhedron_base(Element):
sage: T = polytopes.simplex(3)
sage: T = T.face_truncation(T.faces(0)[0])
sage: T = T.face_truncation(T.faces(0)[0])
sage: T = T.face_truncation(T.faces(0)[1])
sage: T = T.face_truncation(T.faces(0)[2])
sage: T.is_combinatorially_isomorphic(S)
False
sage: T.f_vector(), S.f_vector()
......
cimport cython
from libc.stdint cimport uint64_t
from sage.ext.memory_allocator cimport MemoryAllocator
from sage.structure.sage_object cimport SageObject
from .face_iterator cimport FaceIterator, CombinatorialFace
from .list_of_faces cimport ListOfFaces
from .polyhedron_face_lattice cimport PolyhedronFaceLattice
@cython.final
cdef class CombinatorialPolyhedron(SageObject):
cdef tuple _V # the names of VRep, if they exist
cdef dict _Vinv # dictionary to look up enumeration of vertices
cdef tuple _H # the names of HRep, if they exist
cdef tuple _equalities # stores equalities, given on input (might belong to Hrep)
cdef int _dimension # stores dimension, -2 on init
cdef unsigned int _length_Hrep # Hrep might include equalities
cdef unsigned int _length_Vrepr # Vrep might include rays/lines
cdef size_t _n_facets # length Hrep without equalities
cdef bint _unbounded # ``True`` iff Polyhedron is unbounded
cdef int _n_lines # number of affinely independent lines in the Polyhedron
cdef ListOfFaces bitrep_facets # facets in bit representation
cdef ListOfFaces bitrep_Vrepr # vertices in bit representation
cdef tuple _f_vector
# Edges, ridges and incidences are stored in a pointer of pointers.
# The first edge has vertices ``edges[0][0]`` and ``edges[0][1]``,
# the second edge has vertices ``edges[0][2]`` and ``edges[0][3]``, etc.
# There are ``_length_edges_list`` edges in ``edges[i]``, so the edge
# ``_length_edges_list + 1`` has vertices ``edges[1][0]`` and ``edges[1][1]``.
# Likewise for ridges and incidences.
cdef size_t _length_edges_list
cdef size_t **_edges # stores edges labeled by vertex indices
cdef size_t _n_edges
cdef size_t **_ridges # stores ridges labeld by facet indices
cdef size_t _n_ridges
cdef size_t **_face_lattice_incidences # stores incidences in Hasse diagram labeled indices of the faces
cdef size_t _n_face_lattice_incidences
cdef PolyhedronFaceLattice _all_faces # class to generate Hasse diagram incidences
# Space for edges, ridges, etc. is allocated with ``MemoryAllocators``.
# Upon sucess they are copied to ``_mem_tuple``.
# Thus deallocation (at the correct time) is taken care of.
cdef tuple _mem_tuple
cdef FaceIterator _face_iter(self, bint dual, int dimension)
cdef int _compute_f_vector(self) except -1
cdef int _compute_edges(self, dual) except -1
cdef int _compute_ridges(self, dual) except -1
cdef int _compute_face_lattice_incidences(self) except -1
This diff is collapsed.
/*
#*****************************************************************************
# Copyright (C) 2019 Jonathan Kliem <jonathan.kliem@fu-berlin.de>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) any later version.
# http://www.gnu.org/licenses/
#*****************************************************************************
*/
#include <cstdint>
#include <cstdio>
using namespace std;
/*
The following three functions can be optimized with intrinsics easily.
Enabling the intrinsics is subject of #27103.
The chunksize is the number of vertices/atoms
that can be handled with one operation.
*/
// Any Bit-representation is assumed to be `chunksize`-Bit aligned.
const size_t chunksize = 64;
inline int is_subset(uint64_t *A, uint64_t *B, size_t face_length){
/*
Return ``A & ~B == 0``.
A is not subset of B, iff there is a vertex in A, which is not in B.
``face_length`` is the length of A and B in terms of uint64_t.
*/
for (size_t i = 0; i < face_length; i++){
if (A[i] & ~B[i]){
return 0;
}
}
return 1;
}
inline void intersection(uint64_t *A, uint64_t *B, uint64_t *C, \
size_t face_length){
/*
Set ``C = A & B``, i.e. C is the intersection of A and B.
``face_length`` is the length of A, B and C in terms of uint64_t.
*/
for (size_t i = 0; i < face_length; i++){
C[i] = A[i] & B[i];
}
}
inline size_t count_atoms(uint64_t* A, size_t face_length){
/*
Return the number of atoms/vertices in A.
This is the number of set bits in A.
``face_length`` is the length of A in terms of uint64_t.
*/
unsigned int count = 0;
for (size_t i=0; i<face_length; i++){
uint64_t a = A[i];
while (a){
count += a & 1;
a >>= 1;
}
}
return count;
}
size_t get_next_level(\
uint64_t **faces, const size_t n_faces, uint64_t **maybe_newfaces, \
uint64_t **newfaces, uint64_t **visited_all, \
size_t n_visited_all, size_t face_length){
/*
Set ``newfaces`` to be the facets of ``faces[n_faces -1]``
that are not contained in a face of ``visited_all``.
INPUT:
- ``maybe_newfaces`` -- quasi of type ``uint64_t[n_faces -1][face_length]``,
needs to be ``chunksize``-Bit aligned
- ``newfaces`` -- quasi of type ``*uint64_t[n_faces -1]
- ``visited_all`` -- quasi of type ``*uint64_t[n_visited_all]
- ``face_length`` -- length of the faces
OUTPUT:
- return number of ``newfaces``
- set ``newfaces`` to point to the new faces
ALGORITHM:
To get all facets of ``faces[n_faces-1]``, we would have to:
- Intersect the first ``n_faces-1`` faces of ``faces`` with the last face.
- Add all the intersection of ``visited_all`` with the last face
- Out of both the inclusion-maximal ones are of codimension one, i.e. facets.
As we have visited all faces of ``visited_all``, we alter the algorithm
to not revisit:
Step 1: Intersect the first ``n_faces-1`` faces of ``faces`` with the last face.
Step 2: Out of thosse the inclusion-maximal ones are some of the facets.
At least we obtain all of those, that we have not already visited.
Maybe, we get some more.
Step 3: Only keep those that we have not already visited.
We obtain exactly the facets of ``faces[n_faces-1]`` that we have
not visited yet.
*/
// Step 1:
for (size_t j = 0; j < n_faces - 1; j++){
intersection(faces[j], faces[n_faces - 1], maybe_newfaces[j], face_length);
}
// We keep track, which face in ``maybe_newfaces`` is a new face.
int *is_not_newface = new int[n_faces -1]();
// For each face we will Step 2 and Step 3.
for (size_t j = 0; j < n_faces-1; j++){
// Step 2a:
for(size_t k = 0; k < j; k++){
// Testing if maybe_newfaces[j] is contained in different nextface.
if(is_subset(maybe_newfaces[j], maybe_newfaces[k],face_length)){
// If so, it is not inclusion-maximal and hence not of codimension 1.
is_not_newface[j] = 1;
break;
}
}
if (is_not_newface[j]) {
// No further tests needed, if it is not of codimension 1.
continue;
}
// Step 2b:
for(size_t k = j+1; k < n_faces-1; k++){
// Testing if maybe_newfaces[j] is contained in different nextface.
if(is_subset(maybe_newfaces[j],maybe_newfaces[k], face_length)){
// If so, it is not inclusion-maximal and hence not of codimension 1.
is_not_newface[j] = 1;
break;
}
}
if (is_not_newface[j]) {
// No further tests needed, if it is not of codimension 1.
continue;
}
// Step 3:
for (size_t k = 0; k < n_visited_all; k++){
// Testing if maybe_newfaces[j] is contained in one,
// we have already completely visited.
if(is_subset(maybe_newfaces[j], visited_all[k], face_length)){
// If so, we don't want to revisit.
is_not_newface[j] = 1;
break;
}
}
}
// Set ``newfaces`` to point to the correct ones.
size_t n_newfaces = 0; // length of newfaces2
for (size_t j = 0; j < n_faces -1; j++){
if (is_not_newface[j]) {
// Not a new face of codimension 1.
continue;
}
// It is a new face of codimension 1.
newfaces[n_newfaces] = maybe_newfaces[j];
n_newfaces++;
}
delete[] is_not_newface;
return n_newfaces;
}
size_t bit_repr_to_coatom_repr(uint64_t *face, uint64_t **coatoms, \
size_t n_coatoms, size_t face_length, \
size_t *output){
/*
Write the coatom-representation of face in output. Return length.
``face_length`` is the length of ``face`` and ``coatoms[i]``
in terms of uint64_t.
``n_coatoms`` length of ``coatoms``.
*/
size_t count_length = 0;
for (size_t i = 0; i < n_coatoms; i++){
if (is_subset(face, coatoms[i], face_length)){
// ``face`` is contain in ``coatoms[i]``,
// then ``i`` is an element in the coatom-represention.
output[count_length] = i;
count_length++;
}
}
return count_length;
}
# distutils: language = c++
cimport cython
from libc.stdint cimport uint64_t
cdef extern from "bit_vector_operations.cc":
# Any Bit-representation is assumed to be `chunksize`-Bit aligned.
cdef const size_t chunksize
cdef void intersection(uint64_t *A, uint64_t *B, uint64_t *C,
size_t face_length)
# Return ``A & ~B == 0``.
# A is not subset of B, iff there is a vertex in A, which is not in B.
# ``face_length`` is the length of A and B in terms of uint64_t.
cdef size_t get_next_level(
uint64_t **faces, const size_t n_faces, uint64_t **nextfaces,
uint64_t **nextfaces2, uint64_t **visited_all,
size_t n_visited_all, size_t face_length)
# Set ``newfaces`` to be the facets of ``faces[n_faces -1]``
# that are not contained in a face of ``visited_all``.
# INPUT:
# - ``maybe_newfaces`` -- quasi of type ``uint64_t[n_faces -1][face_length]``,
# needs to be ``chunksize``-Bit aligned
# - ``newfaces`` -- quasi of type ``*uint64_t[n_faces -1]
# - ``visited_all`` -- quasi of type ``*uint64_t[n_visited_all]
# - ``face_length`` -- length of the faces
# OUTPUT:
# - return number of ``newfaces``
# - set ``newfaces`` to point to the new faces
# ALGORITHM:
# To get all facets of ``faces[n_faces-1]``, we would have to:
# - Intersect the first ``n_faces-1`` faces of ``faces`` with the last face.
# - Add all the intersection of ``visited_all`` with the last face
# - Out of both the inclusion-maximal ones are of codimension 1, i.e. facets.
# As we have visited all faces of ``visited_all``, we alter the algorithm
# to not revisit:
# Step 1: Intersect the first ``n_faces-1`` faces of ``faces`` with the last face.
# Step 2: Out of thosse the inclusion-maximal ones are some of the facets.
# At least we obtain all of those, that we have not already visited.
# Maybe, we get some more.
# Step 3: Only keep those that we have not already visited.
# We obtain exactly the facets of ``faces[n_faces-1]`` that we have
# not visited yet.
cdef size_t count_atoms(uint64_t *A, size_t face_length)
# Return the number of atoms/vertices in A.
# This is the number of set bits in A.
# ``face_length`` is the length of A in terms of uint64_t.
cdef size_t bit_repr_to_coatom_repr(
uint64_t *face, uint64_t **coatoms, size_t n_coatoms,
size_t face_length, size_t *output)
# Write the coatom-representation of face in output. Return length.
# ``face_length`` is the length of ``face`` and ``coatoms[i]``
# in terms of uint64_t.
# ``n_coatoms`` length of ``coatoms``.
cimport cython
from libc.stdint cimport uint64_t
from sage.ext.memory_allocator cimport MemoryAllocator
from sage.structure.sage_object cimport SageObject
from .list_of_faces cimport ListOfFaces
from .face_iterator cimport FaceIterator
@cython.final
cdef class CombinatorialFace(SageObject):
cdef readonly bint _dual # if 1, then iterate over dual Polyhedron
cdef ListOfFaces face_mem # constructing face
cdef uint64_t *face # the face in bit-repr
cdef MemoryAllocator _mem
cdef size_t *atom_repr # a place where atom-representaion of face will be stored
cdef size_t *coatom_repr # a place where coatom-representaion of face will be stored
cdef int _dimension # dimension of current face, dual dimension if ``dual``
cdef int _ambient_dimension # dimension of the polyhedron
cdef size_t face_length # stores length of the faces in terms of uint64_t
cdef tuple _V, _H, _equalities # some copies from ``CombinatorialPolyhedron``
cdef size_t _hash_index # an index to give different hashes for all faces of a Polyhedron
# Atoms and coatoms are the vertices/facets of the Polyedron.
# If ``dual == 0``, then coatoms are facets, atoms vertices and vice versa.
cdef ListOfFaces atoms, coatoms
cdef size_t length_atom_repr(self) except -1
cdef size_t set_coatom_repr(self) except -1
cdef size_t set_atom_repr(self) except -1
from libc.stdint cimport uint64_t
cdef int Vrepr_list_to_bit_repr(tuple Vrepr_list, uint64_t *output,
size_t face_length) except -1
cdef int incidences_to_bit_repr(tuple incidences, uint64_t *output,
size_t face_length) except -1
cdef size_t bit_repr_to_Vrepr_list(uint64_t *face, size_t *output,
size_t face_length) except -1
cimport cython
from libc.stdint cimport uint64_t
from sage.ext.memory_allocator cimport MemoryAllocator
from sage.structure.sage_object cimport SageObject
from .list_of_faces cimport ListOfFaces
from .combinatorial_face cimport CombinatorialFace
@cython.final
cdef class FaceIterator(SageObject):
cdef readonly bint dual # if 1, then iterate over dual Polyhedron
cdef uint64_t *face # the current face of the iterator
cdef size_t *atom_repr # a place where atom-representaion of face will be stored
cdef size_t *coatom_repr # a place where coatom-representaion of face will be stored
cdef int current_dimension # dimension of current face, dual dimension if ``dual``
cdef int dimension # dimension of the polyhedron
cdef int n_lines # ``_n_lines`` of ``CombinatorialPolyhedron``
cdef int output_dimension # only faces of this (dual?) dimension are considered
cdef int lowest_dimension # don't consider faces below this (dual?) dimension
cdef size_t _index # this counts the number of seen faces, useful for hasing the faces
cdef MemoryAllocator _mem
cdef tuple newfaces_lists # tuple to hold the ListOfFaces corresponding to maybe_newfaces
cdef size_t face_length # stores length of the faces in terms of uint64_t
cdef tuple _V, _H, _equalities # some copies from ``CombinatorialPolyhedron``
# Atoms and coatoms are the vertices/facets of the Polyedron.
# If ``dual == 0``, then coatoms are facets, atoms vertices and vice versa.
cdef ListOfFaces atoms, coatoms
# ``visited_all`` points to faces, of which we have visited all faces already.
# The number of faces in ``visited_all` might depend on the current dimension:
# Consider we visit the facets A,B of some face F.
# We will first visit all faces of A and then add A to visited_all.
# Then we visit all faces of B and add B to visited_all.
# Then we have visited F completely.
# Instead of having A and B in ``visited_all`` we will point to F.
# In this way, we will append ``visited_all`` in lower dimension, but
# will ignore those changes when going up in dimension again.
# This is why the number of faces in ``visited_all``depends on dimension.
cdef uint64_t **visited_all
cdef size_t *n_visited_all
# ``maybe_newfaces`` is where all possible facets of a face are stored.
# In dimension ``dim`` when visiting all faces of some face,
# the intersections with other faces are stored in ``newfaces2[dim]``.
cdef uint64_t ***maybe_newfaces
# ``newfaces`` will point to those faces in ``maybe_newfaces``
# that are of codimension 1 and not already visited.
cdef uint64_t ***newfaces
cdef size_t *n_newfaces # number of newfaces for each dimension
# After having visited a face completely, we want to add it to ``visited_all``.
# ``first_dim[i]`` will indicate, wether there is one more face in
# ``newfaces[i]`` then ``n_newfaces[i]`` suggests
# that has to be added to ``visited_all``.
# If ``first_time[i] == False``, we still need to
# add ``newfaces[i][n_newfaces[i]]`` to ``visited_all``.
cdef bint *first_time
# The number of elements in newfaces[current_dimension],
# that have not been visited yet.
cdef size_t yet_to_visit
cdef inline CombinatorialFace next_face(self)
cdef inline int next_dimension(self) except -1
cdef inline int next_face_loop(self) except -1
cdef size_t length_atom_repr(self) except -1
cdef size_t set_coatom_repr(self) except -1
cdef size_t set_atom_repr(self) except -1
cimport cython
from libc.stdint cimport uint64_t
from sage.ext.memory_allocator cimport MemoryAllocator
@cython.final
cdef class ListOfFaces:
cdef MemoryAllocator _mem
# ``face_length`` is the length of each face in terms of ``uint64_t``.
cdef readonly size_t n_faces, face_length, n_atoms
# ``data`` points to the raw data.
# It will be of "type" ``uint64_t[n_faces][face_length]``
cdef uint64_t **data
cpdef int compute_dimension(self) except -2
cdef int compute_dimension_loop(self, uint64_t **faces, size_t n_faces,
size_t face_length) except -2
r"""
List of faces
This module provides a class to store faces of a polyhedron in Bit-representation.
This class allocates memory to store the faces in.
A face will be stored as vertex-incidences, where each Bit represents an incidence.
In :mod:`~sage.geometry.polyhedron.combinatorial_polyhedron.conversions` there a methods to actually convert facets of a polyhedron
to bit-representations of vertices stored in :class:`ListOfFaces`.
Moreover, :class:`ListOfFaces` calculates the dimension of a polyhedron, assuming the
faces are the facets of this polyhedron.
Each face is stored over-aligned according to :meth:`~sage.geometry.polyhedron.combinatorial_polyhedron.bit_vector_operations.chunktype`.
.. SEEALSO::
:mod:`sage.geometry.polyhedron.combinatorial_polyhedron.base`.
EXAMPLES:
Provide enough space to store `20` faces as incidences to `60` vertices::
sage: from sage.geometry.polyhedron.combinatorial_polyhedron.list_of_faces \
....: import ListOfFaces
sage: face_list = ListOfFaces(20, 60)
Obtain the facets of a polyhedron::
sage: from sage.geometry.polyhedron.combinatorial_polyhedron.conversions \
....: import incidence_matrix_to_bit_repr_of_facets
sage: P = polytopes.cube()
sage: face_list = incidence_matrix_to_bit_repr_of_facets(P.incidence_matrix())
sage: face_list = incidence_matrix_to_bit_repr_of_facets(P.incidence_matrix())
sage: face_list.compute_dimension()
3
Obtain the Vrepresentation of a polyhedron as facet-incidences::
sage: from sage.geometry.polyhedron.combinatorial_polyhedron.conversions \
....: import incidence_matrix_to_bit_repr_of_Vrepr
sage: P = polytopes.associahedron(['A',3])
sage: face_list = incidence_matrix_to_bit_repr_of_Vrepr(P.incidence_matrix())
sage: face_list.compute_dimension()
3
Obtain the facets of a polyhedron as :class:`ListOfFaces` from a facet list::
sage: from sage.geometry.polyhedron.combinatorial_polyhedron.conversions \
....: import facets_tuple_to_bit_repr_of_facets
sage: facets = ((0,1,2), (0,1,3), (0,2,3), (1,2,3))
sage: face_list = facets_tuple_to_bit_repr_of_facets(facets, 4)
Likewise for the Vrepresenatives as facet-incidences::
sage: from sage.geometry.polyhedron.combinatorial_polyhedron.conversions \
....: import facets_tuple_to_bit_repr_of_Vrepr
sage: facets = ((0,1,2), (0,1,3), (0,2,3), (1,2,3))
sage: face_list = facets_tuple_to_bit_repr_of_Vrepr(facets, 4)
.. SEEALSO::
:mod:`~sage.geometry.polyhedron.combinatorial_polyhedron.base`,
:mod:`~sage.geometry.polyhedron.combinatorial_polyhedron.face_iterator`,
:mod:`~sage.geometry.polyhedron.combinatorial_polyhedron.conversions`,
:mod:`~sage.geometry.polyhedron.combinatorial_polyhedron.polyhedron_faces_lattice`.
AUTHOR:
- Jonathan Kliem (2019-04)
"""
#*****************************************************************************
# Copyright (C) 2019 Jonathan Kliem <jonathan.kliem@fu-berlin.de>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) any later version.
# http://www.gnu.org/licenses/
#*****************************************************************************
from __future__ import absolute_import, division
from sage.structure.element import is_Matrix
from cysignals.signals cimport sig_on, sig_off
from .bit_vector_operations cimport chunksize, get_next_level, count_atoms
cdef extern from "Python.h":
int unlikely(int) nogil # Defined by Cython
cdef class ListOfFaces:
r"""
A class to store the Bit-representation of faces in.
This class will allocate the memory for the faces.
INPUT:
- ``n_faces`` -- the number of faces to be stored
- ``n_atoms`` -- the total number of atoms the faces contain
.. SEEALSO::
:meth:`incidence_matrix_to_bit_repr_of_facets`,
:meth:`incidence_matrix_to_bit_repr_of_Vrepr`,
:meth:`facets_tuple_to_bit_repr_of_facets`,
:meth:`facets_tuple_to_bit_repr_of_Vrepr`,
:class:`~sage.geometry.polyhedron.combinatorial_polyhedron.face_iterator.FaceIterator`,
:class:`~sage.geometry.polyhedron.combinatorial_polyhedron.base.CombinatorialPolyhedron`.
EXAMPLES::
sage: from sage.geometry.polyhedron.combinatorial_polyhedron.list_of_faces \
....: import ListOfFaces
sage: facets = ListOfFaces(5, 13)
sage: facets.face_length in (1, 2, 4)
True
sage: facets.n_atoms
13
sage: facets.n_faces
5
"""
def __init__(self, size_t n_faces, size_t n_atoms):
r"""
Initialize :class:`ListOfFaces`.
See :class:`ListOfFaces`.
TESTS:
Checking for correct alignment of the data::
sage: cython('''
....: from libc.stdint cimport uint64_t
....: from sage.geometry.polyhedron.combinatorial_polyhedron.list_of_faces \
....: cimport ListOfFaces
....:
....: cdef ListOfFaces facets
....: cdef size_t address
....: cdef size_t required_alignment
....:
....: facets = ListOfFaces(10, 13)
....: required_alignment = facets.face_length*8
....: for i in range(10):
....: address = <size_t> facets.data[i]
....: if not address == address & ~(required_alignment - 1):
....: print('Alignment not correct')
....: ''')
sage: TestSuite(sage.geometry.polyhedron.combinatorial_polyhedron.list_of_faces.ListOfFaces).run()
"""
self.n_faces = n_faces
self.n_atoms = n_atoms
self._mem = MemoryAllocator()
# ``data`` will point to the faces as ``*uint64_t``.
self.data = <uint64_t **> self._mem.allocarray(n_faces, sizeof(uint64_t *))
# ``face_length`` is the length in terms of ``uint64_t``
# NOTE: This needs to be divisible by 2, if chunksize is 128
# and divisible by 4, if chunksize is 256.
self.face_length = ((n_atoms - 1)//chunksize + 1)*chunksize//64
cdef size_t i
for i in range(n_faces):
# Allocate the memory for the i-th face.
# We must allocate the memory for ListOfFaces overaligned:
# - must be 16-byte aligned if chunksize = 128
# - must be 32-byte aligned if chunksize = 256
self.data[i] = <uint64_t *> \
self._mem.aligned_malloc(chunksize//8, self.face_length*8)
cpdef int compute_dimension(self) except -2:
r"""
Compute the dimension of a polyhedron by its facets.
This assumes that ``self`` is the list of facets of a polyhedron.
EXAMPLES::
sage: from sage.geometry.polyhedron.combinatorial_polyhedron.list_of_faces \
....: import ListOfFaces
sage: from sage.geometry.polyhedron.combinatorial_polyhedron.conversions \
....: import facets_tuple_to_bit_repr_of_facets, \
....: facets_tuple_to_bit_repr_of_Vrepr
sage: bi_pyr = ((0,1,4), (1,2,4), (2,3,4), (3,0,4),
....: (0,1,5), (1,2,5), (2,3,5), (3,0,5))
sage: facets = facets_tuple_to_bit_repr_of_facets(bi_pyr, 6)
sage: Vrepr = facets_tuple_to_bit_repr_of_Vrepr(bi_pyr, 6)
sage: facets.compute_dimension()
3
sage: Vrepr.compute_dimension()
3
ALGORITHM:
This is done by iteration:
Computes the facets of one of the facets (i.e. the ridges contained in
one of the facets). Then computes the dimension of the facet, by
considering its facets.
Repeats until a face has only one facet. Usually this is a vertex.
However, in the unbounded case, this might be different. The face with only
one facet might be a ray or a line. So the correct dimension of a
polyhedron with one facet is the number of ``[lines, rays, vertices]``
that the facet contains.
Hence, we know the dimension of a face, which has only one facet and
iteratively we know the dimension of entire polyhedron we started from.
TESTS::
sage: from sage.geometry.polyhedron.combinatorial_polyhedron.list_of_faces \
....: import ListOfFaces
sage: from sage.geometry.polyhedron.combinatorial_polyhedron.conversions \
....: import incidence_matrix_to_bit_repr_of_facets, \
....: incidence_matrix_to_bit_repr_of_Vrepr
sage: bi_pyr = ((0,1,4), (1,2,4), (2,3,4), (3,0,4),
....: (0,1,5), (1,2,5), (2,3,5), (3,0,5))
sage: for _ in range(10):
....: points = tuple(tuple(randint(-1000,1000) for _ in range(10))
....: for _ in range(randint(3,15)))
....: P = Polyhedron(vertices=points)
....: facets = incidence_matrix_to_bit_repr_of_facets(P.incidence_matrix())
....: vertices = incidence_matrix_to_bit_repr_of_Vrepr(P.incidence_matrix())
....: d1 = P.dimension()
....: if d1 == 0:
....: continue
....: d2 = facets.compute_dimension()
....: d3 = vertices.compute_dimension()
....: if not d1 == d2 == d3:
....: print('calculation_dimension() seems to be incorrect')
"""
if self.n_faces == 0:
raise TypeError("at least one face needed")
return self.compute_dimension_loop(self.data, self.n_faces, self.face_length)
cdef int compute_dimension_loop(self, uint64_t **faces, size_t n_faces,
size_t face_length) except -2:
r"""
Compute the dimension of a polyhedron by its facets.
INPUT:
- ``faces`` -- facets in Bit-representation
- ``n_faces`` -- length of facesdata
- ``face_length`` -- the length of each face in terms of ``uint64_t``
OUTPUT:
- dimension of the polyhedron
.. SEEALSO::
:meth:`compute_dimension`
"""
if n_faces == 0:
raise TypeError("wrong usage of ``compute_dimension_loop``,\n" +
"at least one face needed.")
if n_faces == 1:
# We expect the face to be the empty polyhedron.
# Possibly it contains more than one vertex/rays/lines.
# The dimension of a polyhedron with this face as only facet is
# the number of atoms it contains.
return count_atoms(faces[0], face_length)
# ``maybe_newfaces`` are all intersection of ``faces[n_faces -1]`` with previous faces.
# It needs to be allcoated to store those faces.
cdef ListOfFaces maybe_newfaces_mem = ListOfFaces(n_faces, face_length*64)
cdef uint64_t **maybe_newfaces = maybe_newfaces_mem.data
# ``newfaces`` point to the actual facets of ``faces[n_faces -1]``.
cdef MemoryAllocator newfaces_mem = MemoryAllocator()
cdef uint64_t **newfaces = <uint64_t **> newfaces_mem.allocarray(n_faces, sizeof(uint64_t *))
# Calculating ``maybe_newfaces`` and ``newfaces``
# such that ``newfaces`` points to all facets of ``faces[n_faces -1]``.
cdef size_t new_n_faces
sig_on()
new_n_faces = get_next_level(faces, n_faces, maybe_newfaces,
newfaces, NULL, 0, face_length)
sig_off()
# compute the dimension of the polyhedron,
# by calculating dimension of one of its faces.
return self.compute_dimension_loop(newfaces, new_n_faces, face_length) + 1
cimport cython
from libc.stdint cimport uint64_t
from sage.ext.memory_allocator cimport MemoryAllocator
from .list_of_faces cimport ListOfFaces
from .combinatorial_face cimport CombinatorialFace
@cython.final
cdef class PolyhedronFaceLattice:
cdef MemoryAllocator _mem
cdef int dimension # dimension of Polyhedron
cdef readonly bint dual # if True, then List of all faces by dual Polyhedron
cdef size_t face_length # stores length of the faces in terms of uint64_t
cdef tuple _V, _H, _equalities # some copies from CombinatorialPolyhedron
cdef size_t *f_vector # a copy of the f-vector, is reversed if dual
cdef size_t *face_counter # how many faces of each dimension have been initialized
cdef size_t *atom_repr # a place where atom-representaion of face will be stored
cdef size_t *coatom_repr # a place where coatom-representaion of face will be stored
# Atoms and coatoms are the Vrepr/facets of the Polyedron.
# If ``dual == 0``, then coatoms are facets, atoms Vrepresentatives and vice versa.
cdef ListOfFaces atoms, coatoms
# All faces are stored in ``faces``. ``faces[i]`` stores all faces of
# dimension `i` in Bit-representation (of atoms).
cdef uint64_t *** faces
cdef tuple faces_mem # tuple to hold the ListOfFaces corresponding to faces
# It follows a number of attributes to iterate over all incidences.
# After initialization, ``PolyhedronFaceLattice`` can iterate over all incidences
# of faces of dimension ``incidence_dim_one`` and ``incidence_dim_two``.
cdef int is_incidence_initialized
cdef int incidence_dim_one
cdef int incidence_dim_two
cdef size_t incidence_counter_one # walks trough faces of incidence_dim_one
cdef size_t incidence_counter_two # walks through all indices of coatoms (for each face in incidence_dim_one)
# Intersection of ``faces[incidence_dim_one][incidence_counter_one]`` with
# ``coatoms[incidence_counter_two]``.
# If this is contained in ``faces[incidence_dim_two]``, there is an incidence.
cdef uint64_t *incidence_face
cdef int _add_face(self, int face_dim, uint64_t *face) except -1
cdef int _sort(self) except -1
cdef int _sort_one_list(self, uint64_t **faces, size_t n_faces) except -1
cdef int _sort_one_list_loop(
self, uint64_t **inp, uint64_t **output1,
uint64_t **output2, size_t n_faces) except -1
cdef inline size_t find_face(self, int dimension, uint64_t *face) except -1
cdef inline bint is_smaller(self, uint64_t *one, uint64_t *two)
cdef inline int is_equal(self, int dimension, size_t index,
uint64_t *face) except -1
cdef CombinatorialFace get_face(self, int dimension, size_t index)
cdef size_t set_coatom_repr(self, int dimension, size_t index) except -1
cdef size_t set_atom_repr(self, int dimension, size_t index) except -1
cdef void incidence_init(self, int dimension_one, int dimension_two)
cdef inline bint next_incidence(self, size_t *one, size_t *two)
cdef inline bint next_incidence_loop(self, size_t *one, size_t *two)
cdef inline bint next_trivial_incidence(self, size_t *one, size_t *two)
cdef inline bint next_trivial_incidence2(self, size_t *one, size_t *two)
......@@ -100,15 +100,15 @@ but only one generating line::
sage: strip.lines()
(A line in the direction (0, 1),)
sage: [f.ambient_V_indices() for f in strip.faces(1)]
[(0, 1), (0, 2)]
[(0, 2), (0, 1)]
sage: for face in strip.faces(1):
....: print(face.ambient_V_indices())
(0, 1)
(0, 2)
(0, 1)
sage: for face in strip.faces(1):
....: print("{} = {}".format(face.ambient_V_indices(), face.as_polyhedron().Vrepresentation()))
(0, 1) = (A line in the direction (0, 1), A vertex at (-1, 0))
(0, 2) = (A line in the direction (0, 1), A vertex at (1, 0))
(0, 1) = (A line in the direction (0, 1), A vertex at (-1, 0))
EXAMPLES::
......