Skip to content
This repository was archived by the owner on Feb 1, 2023. It is now read-only.

Commit d1a1a28

Browse files
author
Release Manager
committed
Trac #30443: Simplify setting and getting "edges" of edges, ridges, incidences in CombinatorialPolyhedron
In `CombinatorialPolyhedron` the same very basic `DiGraph` data structure is used for three different purposes: - edges, - ridges, - incidences. We collect setting and getting of edges in two methods to reduce code duplication. Background: The idea is to collect edges of a graph almost without overhead. Currently up to `16348` edges are saved in a list of length `2*16348*sizeof(size_t)`. To allow more edges (while avoiding large chunks of continuous memory), we keep the edges in a lists of lists. URL: https://trac.sagemath.org/30443 Reported by: gh-kliem Ticket author(s): Jonathan Kliem Reviewer(s): Travis Scrimshaw
2 parents f8c4e4b + bde0945 commit d1a1a28

File tree

2 files changed

+85
-124
lines changed

2 files changed

+85
-124
lines changed

src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pxd

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,3 +67,6 @@ cdef class CombinatorialPolyhedron(SageObject):
6767
cdef int _compute_edges(self, dual) except -1
6868
cdef int _compute_ridges(self, dual) except -1
6969
cdef int _compute_face_lattice_incidences(self) except -1
70+
71+
cdef inline int _set_edge(self, size_t a, size_t b, size_t ***edges_pt, size_t *counter_pt, size_t *current_length_pt, MemoryAllocator mem) except -1
72+
cdef inline size_t _get_edge(self, size_t **edges, size_t edge_number, size_t vertex) except -1

src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx

Lines changed: 82 additions & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -1169,7 +1169,6 @@ cdef class CombinatorialPolyhedron(SageObject):
11691169
('a', 'c'),
11701170
('a', 'b'))
11711171
"""
1172-
cdef size_t len_edge_list = self._length_edges_list
11731172
if self._edges is NULL:
11741173
# compute the edges.
11751174
if not self.is_bounded():
@@ -1184,15 +1183,6 @@ cdef class CombinatorialPolyhedron(SageObject):
11841183
if self._edges is NULL:
11851184
raise ValueError('could not determine edges')
11861185

1187-
# The edges are being saved in a list basically.
1188-
# The first entry represents the first vertex of the first edge.
1189-
# The second entry represents the second vertex of that edge.
1190-
# The third entry represents the first vertex of the second edge etc.
1191-
1192-
# Possibly there are many edges.
1193-
# Hence, edges are stored in an array of arrays,
1194-
# with each array containing ``len_edge_list`` of edges.
1195-
11961186
# Mapping the indices of the Vrep to the names, if requested.
11971187
if self.Vrep() is not None and names is True:
11981188
def f(size_t i): return self.Vrep()[i]
@@ -1201,9 +1191,9 @@ cdef class CombinatorialPolyhedron(SageObject):
12011191

12021192
# Getting the indices of the `i`-th edge.
12031193
def vertex_one(size_t i):
1204-
return f(self._edges[i // len_edge_list][2*(i % len_edge_list)])
1194+
return f(self._get_edge(self._edges, i, 0))
12051195
def vertex_two(size_t i):
1206-
return f(self._edges[i // len_edge_list][2*(i % len_edge_list)+1])
1196+
return f(self._get_edge(self._edges, i, 1))
12071197

12081198
cdef size_t j
12091199
return tuple((vertex_one(j), vertex_two(j)) for j in range(self._n_edges))
@@ -1351,7 +1341,6 @@ cdef class CombinatorialPolyhedron(SageObject):
13511341
sage: C.ridges(names=False, add_equalities=True)
13521342
((2, 3), (1, 3), (0, 3), (1, 2), (0, 2), (0, 1))
13531343
"""
1354-
cdef size_t len_ridge_list = self._length_edges_list
13551344
if self._ridges is NULL:
13561345
# compute the ridges.
13571346
if not self.is_bounded():
@@ -1367,15 +1356,6 @@ cdef class CombinatorialPolyhedron(SageObject):
13671356
raise ValueError('could not determine ridges')
13681357
n_ridges = self._n_ridges
13691358

1370-
# The ridges are being saved in a list basically.
1371-
# The first entry represents the first facet of the first ridge.
1372-
# The second entry represents the second facet of that ridge.
1373-
# The third entry represents the first facet of the second ridge etc.
1374-
1375-
# Possibly there are many ridges.
1376-
# Hence, ridges are stored in an array of arrays,
1377-
# with each array containing ``len_ridge_list`` of ridges.
1378-
13791359
# Mapping the indices of the Vepr to the names, if requested.
13801360
if self.facet_names() is not None and names is True:
13811361
def f(size_t i): return self.facet_names()[i]
@@ -1384,9 +1364,9 @@ cdef class CombinatorialPolyhedron(SageObject):
13841364

13851365
# Getting the indices of the `i`-th ridge.
13861366
def facet_one(size_t i):
1387-
return f(self._ridges[i // len_ridge_list][2*(i % len_ridge_list)])
1367+
return f(self._get_edge(self._ridges, i, 0))
13881368
def facet_two(size_t i):
1389-
return f(self._ridges[i // len_ridge_list][2*(i % len_ridge_list)+1])
1369+
return f(self._get_edge(self._ridges, i, 1))
13901370

13911371
cdef size_t j
13921372
if add_equalities and names:
@@ -2491,27 +2471,17 @@ cdef class CombinatorialPolyhedron(SageObject):
24912471

24922472
cdef size_t **incidences = self._face_lattice_incidences
24932473
cdef size_t n_incidences = self._n_face_lattice_incidences
2494-
cdef size_t len_incidence_list = self._length_edges_list
2495-
2496-
# The incidences are being saved in a list basically.
2497-
# The first entry represents the first face of the first incidence.
2498-
# The second entry represents the second face of that incidence.
2499-
# The third entry represents the first face of the second incidence etc.
2500-
2501-
# Possibly there are many incidences.
2502-
# Hence, incidences are stored in an array of arrays,
2503-
# with each array containing ``len_incidence_list`` of incidences.
25042474

25052475
# Getting the indices of the `i`-th incidence.
25062476
def face_one(size_t i):
2507-
return smallInteger(incidences[i // len_incidence_list][2*(i % len_incidence_list)])
2477+
return smallInteger(self._get_edge(incidences, i, 0))
25082478
def face_two(size_t i):
2509-
return smallInteger(incidences[i // len_incidence_list][2*(i % len_incidence_list)+1])
2479+
return smallInteger(self._get_edge(incidences, i, 1))
25102480

25112481
# Edges of the face-lattice/Hasse diagram.
25122482
cdef size_t j
25132483
edges = tuple((face_one(j), face_two(j))
2514-
for j in range(n_incidences))
2484+
for j in range(n_incidences))
25152485

25162486
V = tuple(smallInteger(i) for i in range(sum(self._f_vector)))
25172487

@@ -3002,20 +2972,17 @@ cdef class CombinatorialPolyhedron(SageObject):
30022972

30032973
cdef MemoryAllocator mem = MemoryAllocator()
30042974
cdef FaceIterator face_iter
3005-
cdef size_t len_edge_list = self._length_edges_list
30062975
cdef int dim = self.dimension()
30072976
cdef int d # dimension of the current face of ``FaceIterator``
30082977
cdef size_t *f_vector # compute f_vector, if not done already
30092978
cdef bint is_f_vector # True if f_vector was computed previously
30102979

3011-
# For each edge we determine its location in ``edges``
3012-
# by ``edges[one][two]``
3013-
cdef size_t **edges = <size_t**> mem.malloc(sizeof(size_t*))
3014-
cdef size_t one, two
3015-
2980+
cdef size_t **edges = <size_t**> mem.malloc(sizeof(size_t**))
30162981
cdef size_t counter = 0 # the number of edges so far
30172982
cdef size_t current_length = 1 # dynamically enlarge **edges
30182983

2984+
cdef size_t a,b # vertices of an edge
2985+
30192986
if self._f_vector:
30202987
is_f_vector = True
30212988
else:
@@ -3024,10 +2991,7 @@ cdef class CombinatorialPolyhedron(SageObject):
30242991

30252992
if dim == 1:
30262993
# In this case there is an edge, but its not a proper face.
3027-
edges[0] = <size_t *> mem.allocarray(2, sizeof(size_t))
3028-
edges[0][0] = 0
3029-
edges[0][1] = 1
3030-
counter = 1
2994+
self._set_edge(0, 1, &edges, &counter, &current_length, mem)
30312995

30322996
# Success, copy the data to ``CombinatorialPolyhedron``.
30332997
if dual:
@@ -3081,27 +3045,13 @@ cdef class CombinatorialPolyhedron(SageObject):
30813045
# If not, there won't even be any edges. Prevent error message.
30823046

30833047
while (face_iter.next_dimension() == 1):
3084-
3085-
# Determine the position in ``edges``.
3086-
one = counter // len_edge_list
3087-
two = counter % len_edge_list
3088-
3089-
# Enlarge ``edges`` if needed.
3090-
if unlikely(two == 0):
3091-
if unlikely(one + 1 > current_length):
3092-
# enlarge **edges
3093-
current_length *= 2
3094-
edges = <size_t **> mem.reallocarray(edges, current_length, sizeof(size_t*))
3095-
3096-
edges[one] = <size_t *> mem.allocarray(2 * len_edge_list, sizeof(size_t))
3097-
30983048
# Set up face_iter.atom_rep
30993049
face_iter.set_atom_rep()
31003050

31013051
# Copy the information.
3102-
edges[one][2*two] = face_iter.structure.atom_rep[0]
3103-
edges[one][2*two + 1] = face_iter.structure.atom_rep[1]
3104-
counter += 1
3052+
a = face_iter.structure.atom_rep[0]
3053+
b = face_iter.structure.atom_rep[1]
3054+
self._set_edge(a, b, &edges, &counter, &current_length, mem)
31053055

31063056
# Success, copy the data to ``CombinatorialPolyhedron``.
31073057
if dual:
@@ -3134,26 +3084,13 @@ cdef class CombinatorialPolyhedron(SageObject):
31343084
if d == 1:
31353085
# If it is an edge.
31363086

3137-
# Determine the position in ``edges``.
3138-
one = counter // len_edge_list
3139-
two = counter % len_edge_list
3140-
3141-
# Enlarge ``edges`` if needed.
3142-
if unlikely(two == 0):
3143-
if unlikely(one + 1 > current_length):
3144-
# enlarge **edges
3145-
current_length *= 2
3146-
edges = <size_t **> mem.reallocarray(edges, current_length, sizeof(size_t*))
3147-
3148-
edges[one] = <size_t *> mem.allocarray(2 * len_edge_list, sizeof(size_t))
3149-
31503087
# Set up face_iter.atom_rep
31513088
face_iter.set_atom_rep()
31523089

31533090
# Copy the information.
3154-
edges[one][2*two] = face_iter.structure.atom_rep[0]
3155-
edges[one][2*two + 1] = face_iter.structure.atom_rep[1]
3156-
counter += 1
3091+
a = face_iter.structure.atom_rep[0]
3092+
b = face_iter.structure.atom_rep[1]
3093+
self._set_edge(a, b, &edges, &counter, &current_length, mem)
31573094

31583095
d = face_iter.next_dimension() # Go to next face.
31593096

@@ -3188,23 +3125,20 @@ cdef class CombinatorialPolyhedron(SageObject):
31883125

31893126
cdef MemoryAllocator mem = MemoryAllocator()
31903127
cdef FaceIterator face_iter
3191-
cdef size_t len_ridge_list = self._length_edges_list
31923128
cdef int dim = self.dimension()
31933129

31943130
# For each ridge we determine its location in ``ridges``
31953131
# by ``ridges[one][two]``.
3196-
cdef size_t **ridges = <size_t**> mem.malloc(sizeof(size_t*))
3197-
cdef size_t one, two
3132+
cdef size_t **ridges = <size_t**> mem.malloc(sizeof(size_t**))
31983133

31993134
cdef size_t counter = 0 # the number of ridges so far
32003135
cdef size_t current_length = 1 # dynamically enlarge **ridges
32013136

3137+
cdef size_t a,b # facets of a ridge
3138+
32023139
if dim == 1 and self.n_facets() > 1:
32033140
# In this case there is a ridge, but its not a proper face.
3204-
ridges[0] = <size_t *> mem.allocarray(2, sizeof(size_t))
3205-
ridges[0][0] = 0
3206-
ridges[0][1] = 1
3207-
counter = 1
3141+
self._set_edge(0, 1, &ridges, &counter, &current_length, mem)
32083142

32093143
# Success, copy the data to ``CombinatorialPolyhedron``.
32103144
if not dual:
@@ -3254,27 +3188,13 @@ cdef class CombinatorialPolyhedron(SageObject):
32543188
# Prevent error message.
32553189

32563190
while (face_iter.next_dimension() == dim - 2):
3257-
3258-
# Determine the position in ``ridges``.
3259-
one = counter // len_ridge_list
3260-
two = counter % len_ridge_list
3261-
3262-
# Enlarge ``ridges`` if needed.
3263-
if unlikely(two == 0):
3264-
if unlikely(one + 1 > current_length):
3265-
# enlarge **ridges
3266-
current_length *= 2
3267-
ridges = <size_t **> mem.reallocarray(ridges, current_length, sizeof(size_t*))
3268-
3269-
ridges[one] = <size_t *> mem.allocarray(2 * len_ridge_list, sizeof(size_t))
3270-
32713191
# Set up face_iter.coatom_rep
32723192
face_iter.set_coatom_rep()
32733193

32743194
# Copy the information.
3275-
ridges[one][2*two] = face_iter.structure.coatom_rep[0]
3276-
ridges[one][2*two + 1] = face_iter.structure.coatom_rep[1]
3277-
counter += 1
3195+
a = face_iter.structure.coatom_rep[0]
3196+
b = face_iter.structure.coatom_rep[1]
3197+
self._set_edge(a, b, &ridges, &counter, &current_length, mem)
32783198

32793199
# Success, copy the data to ``CombinatorialPolyhedron``.
32803200
if not dual:
@@ -3327,7 +3247,6 @@ cdef class CombinatorialPolyhedron(SageObject):
33273247
# For each incidence we determine its location in ``incidences``
33283248
# by ``incidences[one][two]``.
33293249
cdef size_t **incidences = <size_t**> mem.malloc(sizeof(size_t*))
3330-
cdef size_t one, two
33313250

33323251
cdef size_t counter = 0 # the number of incidences so far
33333252
cdef size_t current_length = 1 # dynamically enlarge **incidences
@@ -3355,33 +3274,16 @@ cdef class CombinatorialPolyhedron(SageObject):
33553274

33563275
# Get all incidences for fixed ``[dimension_one, dimension_two]``.
33573276
while all_faces.next_incidence(&second, &first):
3358-
3359-
# Determine the position in ``incidences``.
3360-
one = counter // len_incidence_list
3361-
two = counter % len_incidence_list
3362-
3363-
# Enlarge ``incidences`` if needed.
3364-
if unlikely(two == 0):
3365-
if unlikely(one + 1 > current_length):
3366-
# enlarge **incidences
3367-
current_length *= 2
3368-
incidences = <size_t **> mem.reallocarray(incidences, current_length, sizeof(size_t*))
3369-
3370-
incidences[one] = <size_t *> mem.allocarray(2 * len_incidence_list, sizeof(size_t))
3371-
33723277
if all_faces.dual:
33733278
# If ``dual``, then ``second`` and ``first are flipped.
33743279
second += already_seen
33753280
first += already_seen_next
3376-
incidences[one][2*two] = second
3377-
incidences[one][2*two + 1] = first
3281+
self._set_edge(second, first, &incidences, &counter, &current_length, mem)
33783282
else:
33793283
second += already_seen_next
33803284
first += already_seen
3381-
incidences[one][2*two] = first
3382-
incidences[one][2*two + 1] = second
3285+
self._set_edge(first, second, &incidences, &counter, &current_length, mem)
33833286

3384-
counter += 1
33853287
sig_check()
33863288

33873289
# Increase dimensions.
@@ -3395,6 +3297,62 @@ cdef class CombinatorialPolyhedron(SageObject):
33953297
self._face_lattice_incidences = incidences
33963298
sig_unblock()
33973299

3300+
cdef inline int _set_edge(self, size_t a, size_t b, size_t ***edges_pt, size_t *counter_pt, size_t *current_length_pt, MemoryAllocator mem) except -1:
3301+
r"""
3302+
Set an edge in an edge list.
3303+
3304+
Sets the values of all pointers accordingly.
3305+
3306+
INPUT:
3307+
3308+
- ``a``,``b`` -- the vertices of the edge
3309+
- ``edges_pt`` -- pointer to the list of lists; might point to ``NULL``
3310+
when ``current_length_pt[0] == 0``
3311+
- ``counter_pt`` -- pointer to the number of edges
3312+
- ``current_length_pt`` -- pointer to the length of ``edges_pt[0]``
3313+
- ``mem`` -- ``MemoryAllocator`` used for allocation
3314+
"""
3315+
cdef size_t len_edge_list = self._length_edges_list
3316+
# Determine the position in ``edges``.
3317+
cdef size_t one = counter_pt[0] // len_edge_list
3318+
cdef size_t two = counter_pt[0] % len_edge_list
3319+
3320+
if unlikely(current_length_pt[0] == 0):
3321+
edges_pt[0] = <size_t**> mem.malloc(sizeof(size_t*))
3322+
current_length_pt[0] = 1
3323+
3324+
# Enlarge ``edges`` if needed.
3325+
if unlikely(two == 0):
3326+
if unlikely(one + 1 > current_length_pt[0]):
3327+
# enlarge **edges
3328+
current_length_pt[0] = 2*current_length_pt[0]
3329+
edges_pt[0] = <size_t **> mem.reallocarray(edges_pt[0], current_length_pt[0], sizeof(size_t*))
3330+
3331+
edges_pt[0][one] = <size_t *> mem.allocarray(2 * len_edge_list, sizeof(size_t))
3332+
3333+
edges_pt[0][one][2*two] = a
3334+
edges_pt[0][one][2*two + 1] = b
3335+
counter_pt[0] = counter_pt[0] + 1
3336+
3337+
cdef inline size_t _get_edge(self, size_t **edges, size_t edge_number, size_t vertex) except -1:
3338+
r"""
3339+
Get a vertex of an edge in an edge list.
3340+
3341+
INPUT:
3342+
3343+
- ``edges`` -- the edges list
3344+
- ``edge_number`` -- the number of the edge to obtain
3345+
- ``vertex`` -- one of ``0``, ``1``; the vertex to obtain
3346+
3347+
OUTPUT: The specified vertex of the specified edge.
3348+
"""
3349+
cdef size_t len_edge_list = self._length_edges_list
3350+
# Determine the position in ``edges``.
3351+
cdef size_t one = edge_number // len_edge_list
3352+
cdef size_t two = edge_number % len_edge_list
3353+
3354+
return edges[one][2*two + vertex]
3355+
33983356
def _record_all_faces(self):
33993357
r"""
34003358
Initialize :class:`~sage.geometry.polyhedron.combinatorial_polyhedron.polyhedron_faces_lattice.PolyhedronFaceLattice` for the polyhedron.

0 commit comments

Comments
 (0)