Skip to content

Commit f2bdadf

Browse files
author
Release Manager
committed
gh-39312: use memory allocator in `sage/coding/binary_code.pyx` As discussed in #39229, we use MemoryAllocator in `sage/coding/binary_code.pyx` to simplify parts of the code. ### 📝 Checklist <!-- Put an `x` in all the boxes that apply. --> - [x] The title is concise and informative. - [x] The description explains in detail what this PR is about. - [x] I have linked a relevant issue or discussion. - [ ] I have created tests covering the changes. - [ ] I have updated the documentation and checked the documentation preview. ### ⌛ Dependencies <!-- List all open PRs that this PR logically depends on. For example, --> <!-- - #12345: short description why this is a dependency --> <!-- - #34567: ... --> URL: #39312 Reported by: David Coudert Reviewer(s): David Coudert, Kwankyu Lee
2 parents 66d1d42 + 46ff10f commit f2bdadf

File tree

2 files changed

+60
-194
lines changed

2 files changed

+60
-194
lines changed

src/sage/coding/binary_code.pxd

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from memory_allocator cimport MemoryAllocator
2+
13
cdef int *hamming_weights() noexcept
24

35
ctypedef unsigned int codeword
@@ -11,6 +13,7 @@ cdef struct WordPermutation:
1113
codeword gate
1214

1315
cdef class BinaryCode:
16+
cdef MemoryAllocator mem
1417
cdef codeword *basis
1518
cdef codeword *words
1619
cdef int ncols
@@ -34,6 +37,7 @@ cdef codeword permute_word_by_wp(WordPermutation *, codeword) noexcept
3437
cdef codeword *expand_to_ortho_basis(BinaryCode, int) noexcept
3538

3639
cdef class OrbitPartition:
40+
cdef MemoryAllocator mem
3741
cdef int nwords
3842
cdef int ncols
3943
cdef int *wd_parent
@@ -52,6 +56,7 @@ cdef class OrbitPartition:
5256
cdef int merge_perm(self, int *, int *) noexcept
5357

5458
cdef class PartitionStack:
59+
cdef MemoryAllocator mem
5560
cdef int *wd_ents
5661
cdef int *wd_lvls
5762
cdef int *col_ents
@@ -89,6 +94,7 @@ cdef class PartitionStack:
8994
cdef void get_permutation(self, PartitionStack, int *, int *) noexcept
9095

9196
cdef class BinaryCodeClassifier:
97+
cdef MemoryAllocator mem
9298
cdef int *ham_wts
9399
cdef int L
94100
cdef unsigned int *Phi

src/sage/coding/binary_code.pyx

Lines changed: 54 additions & 194 deletions
Original file line numberDiff line numberDiff line change
@@ -123,8 +123,9 @@ def weight_dist(M):
123123
cdef bitset_t word
124124
cdef int i,j,k, dim=M.nrows(), deg=M.ncols()
125125
cdef list L
126-
cdef int *LL = <int *> sig_malloc((deg+1) * sizeof(int))
127-
cdef bitset_s *basis = <bitset_s *> sig_malloc(dim * sizeof(bitset_s))
126+
cdef MemoryAllocator mem = MemoryAllocator()
127+
cdef int *LL = <int *> mem.malloc((deg+1) * sizeof(int))
128+
cdef bitset_s *basis = <bitset_s *> mem.malloc(dim * sizeof(bitset_s))
128129
for i from 0 <= i < dim:
129130
bitset_init(&basis[i], deg)
130131
bitset_zero(&basis[i])
@@ -150,8 +151,6 @@ def weight_dist(M):
150151
L = [int(LL[i]) for i from 0 <= i < deg+1]
151152
for i from 0 <= i < dim:
152153
bitset_free(&basis[i])
153-
sig_free(LL)
154-
sig_free(basis)
155154
return L
156155

157156

@@ -785,12 +784,9 @@ cdef class BinaryCode:
785784
if self.nrows >= self.radix or self.ncols > self.radix:
786785
raise NotImplementedError("Columns and rows are stored as ints. This code is too big.")
787786

788-
self.words = <codeword *> sig_malloc( nwords * sizeof(int) )
789-
self.basis = <codeword *> sig_malloc( nrows * sizeof(int) )
790-
if self.words is NULL or self.basis is NULL:
791-
if self.words is not NULL: sig_free(self.words)
792-
if self.basis is not NULL: sig_free(self.basis)
793-
raise MemoryError("Memory.")
787+
self.mem = MemoryAllocator()
788+
self.words = <codeword *> self.mem.malloc(nwords * sizeof(int))
789+
self.basis = <codeword *> self.mem.malloc(nrows * sizeof(int))
794790
self_words = self.words
795791
self_basis = self.basis
796792

@@ -829,10 +825,6 @@ cdef class BinaryCode:
829825
for combination from 0 <= combination < other_nwords:
830826
self_words[combination+other_nwords] = self_words[combination] ^ glue_word
831827

832-
def __dealloc__(self):
833-
sig_free(self.words)
834-
sig_free(self.basis)
835-
836828
def __reduce__(self):
837829
"""
838830
Method for pickling and unpickling BinaryCodes.
@@ -1279,35 +1271,15 @@ cdef class OrbitPartition:
12791271
nwords = (1 << nrows)
12801272
self.nwords = nwords
12811273
self.ncols = ncols
1282-
self.wd_parent = <int *> sig_malloc(nwords * sizeof(int))
1283-
self.wd_rank = <int *> sig_malloc(nwords * sizeof(int))
1284-
self.wd_min_cell_rep = <int *> sig_malloc(nwords * sizeof(int))
1285-
self.wd_size = <int *> sig_malloc(nwords * sizeof(int))
1286-
self.col_parent = <int *> sig_malloc(ncols * sizeof(int))
1287-
self.col_rank = <int *> sig_malloc(ncols * sizeof(int))
1288-
self.col_min_cell_rep = <int *> sig_malloc(ncols * sizeof(int))
1289-
self.col_size = <int *> sig_malloc(ncols * sizeof(int))
1290-
if (self.wd_parent is NULL or self.wd_rank is NULL
1291-
or self.wd_min_cell_rep is NULL or self.wd_size is NULL
1292-
or self.col_parent is NULL or self.col_rank is NULL
1293-
or self.col_min_cell_rep is NULL or self.col_size is NULL):
1294-
if self.wd_parent is not NULL:
1295-
sig_free(self.wd_parent)
1296-
if self.wd_rank is not NULL:
1297-
sig_free(self.wd_rank)
1298-
if self.wd_min_cell_rep is not NULL:
1299-
sig_free(self.wd_min_cell_rep)
1300-
if self.wd_size is not NULL:
1301-
sig_free(self.wd_size)
1302-
if self.col_parent is not NULL:
1303-
sig_free(self.col_parent)
1304-
if self.col_rank is not NULL:
1305-
sig_free(self.col_rank)
1306-
if self.col_min_cell_rep is not NULL:
1307-
sig_free(self.col_min_cell_rep)
1308-
if self.col_size is not NULL:
1309-
sig_free(self.col_size)
1310-
raise MemoryError("Memory.")
1274+
self.mem = MemoryAllocator()
1275+
self.wd_parent = <int *> self.mem.malloc(nwords * sizeof(int))
1276+
self.wd_rank = <int *> self.mem.malloc(nwords * sizeof(int))
1277+
self.wd_min_cell_rep = <int *> self.mem.malloc(nwords * sizeof(int))
1278+
self.wd_size = <int *> self.mem.malloc(nwords * sizeof(int))
1279+
self.col_parent = <int *> self.mem.malloc(ncols * sizeof(int))
1280+
self.col_rank = <int *> self.mem.malloc(ncols * sizeof(int))
1281+
self.col_min_cell_rep = <int *> self.mem.malloc(ncols * sizeof(int))
1282+
self.col_size = <int *> self.mem.malloc(ncols * sizeof(int))
13111283
for word from 0 <= word < nwords:
13121284
self.wd_parent[word] = word
13131285
self.wd_rank[word] = 0
@@ -1319,16 +1291,6 @@ cdef class OrbitPartition:
13191291
self.col_min_cell_rep[col] = col
13201292
self.col_size[col] = 1
13211293

1322-
def __dealloc__(self):
1323-
sig_free(self.wd_parent)
1324-
sig_free(self.wd_rank)
1325-
sig_free(self.wd_min_cell_rep)
1326-
sig_free(self.wd_size)
1327-
sig_free(self.col_parent)
1328-
sig_free(self.col_rank)
1329-
sig_free(self.col_min_cell_rep)
1330-
sig_free(self.col_size)
1331-
13321294
def __repr__(self):
13331295
"""
13341296
Return a string representation of the orbit partition.
@@ -1614,44 +1576,19 @@ cdef class PartitionStack:
16141576
self.flag = (1 << (self.radix-1))
16151577

16161578
# data
1617-
self.wd_ents = <int *> sig_malloc(self.nwords * sizeof_int)
1618-
self.wd_lvls = <int *> sig_malloc(self.nwords * sizeof_int)
1619-
self.col_ents = <int *> sig_malloc(self.ncols * sizeof_int)
1620-
self.col_lvls = <int *> sig_malloc(self.ncols * sizeof_int)
1579+
self.mem = MemoryAllocator()
1580+
self.wd_ents = <int *> self.mem.malloc(self.nwords * sizeof_int)
1581+
self.wd_lvls = <int *> self.mem.malloc(self.nwords * sizeof_int)
1582+
self.col_ents = <int *> self.mem.malloc(self.ncols * sizeof_int)
1583+
self.col_lvls = <int *> self.mem.malloc(self.ncols * sizeof_int)
16211584

16221585
# scratch space
1623-
self.col_degs = <int *> sig_malloc( self.ncols * sizeof_int )
1624-
self.col_counts = <int *> sig_malloc( self.nwords * sizeof_int )
1625-
self.col_output = <int *> sig_malloc( self.ncols * sizeof_int )
1626-
self.wd_degs = <int *> sig_malloc( self.nwords * sizeof_int )
1627-
self.wd_counts = <int *> sig_malloc( (self.ncols+1) * sizeof_int )
1628-
self.wd_output = <int *> sig_malloc( self.nwords * sizeof_int )
1629-
1630-
if self.wd_ents is NULL or self.wd_lvls is NULL or self.col_ents is NULL \
1631-
or self.col_lvls is NULL or self.col_degs is NULL or self.col_counts is NULL \
1632-
or self.col_output is NULL or self.wd_degs is NULL or self.wd_counts is NULL \
1633-
or self.wd_output is NULL:
1634-
if self.wd_ents is not NULL:
1635-
sig_free(self.wd_ents)
1636-
if self.wd_lvls is not NULL:
1637-
sig_free(self.wd_lvls)
1638-
if self.col_ents is not NULL:
1639-
sig_free(self.col_ents)
1640-
if self.col_lvls is not NULL:
1641-
sig_free(self.col_lvls)
1642-
if self.col_degs is not NULL:
1643-
sig_free(self.col_degs)
1644-
if self.col_counts is not NULL:
1645-
sig_free(self.col_counts)
1646-
if self.col_output is not NULL:
1647-
sig_free(self.col_output)
1648-
if self.wd_degs is not NULL:
1649-
sig_free(self.wd_degs)
1650-
if self.wd_counts is not NULL:
1651-
sig_free(self.wd_counts)
1652-
if self.wd_output is not NULL:
1653-
sig_free(self.wd_output)
1654-
raise MemoryError("Memory.")
1586+
self.col_degs = <int *> self.mem.malloc( self.ncols * sizeof_int )
1587+
self.col_counts = <int *> self.mem.malloc( self.nwords * sizeof_int )
1588+
self.col_output = <int *> self.mem.malloc( self.ncols * sizeof_int )
1589+
self.wd_degs = <int *> self.mem.malloc( self.nwords * sizeof_int )
1590+
self.wd_counts = <int *> self.mem.malloc( (self.ncols+1) * sizeof_int )
1591+
self.wd_output = <int *> self.mem.malloc( self.nwords * sizeof_int )
16551592

16561593
nwords = self.nwords
16571594
ncols = self.ncols
@@ -1694,17 +1631,8 @@ cdef class PartitionStack:
16941631
wd_output[k]=0
16951632

16961633
def __dealloc__(self):
1697-
if self.basis_locations: sig_free(self.basis_locations)
1698-
sig_free(self.wd_ents)
1699-
sig_free(self.wd_lvls)
1700-
sig_free(self.col_ents)
1701-
sig_free(self.col_lvls)
1702-
sig_free(self.col_degs)
1703-
sig_free(self.col_counts)
1704-
sig_free(self.col_output)
1705-
sig_free(self.wd_degs)
1706-
sig_free(self.wd_counts)
1707-
sig_free(self.wd_output)
1634+
if self.basis_locations:
1635+
sig_free(self.basis_locations)
17081636

17091637
def print_data(self):
17101638
"""
@@ -3045,17 +2973,12 @@ cdef class PartitionStack:
30452973
([0, 1, 2, 3, 4, 5, 6, 7, 12, 13, 14, 15, 8, 9, 10, 11], [0, 1, 2, 3, 5, 4, 7, 6])
30462974
"""
30472975
cdef int i
3048-
cdef int *word_g = <int *> sig_malloc( self.nwords * sizeof(int) )
3049-
cdef int *col_g = <int *> sig_malloc( self.ncols * sizeof(int) )
3050-
if word_g is NULL or col_g is NULL:
3051-
if word_g is not NULL: sig_free(word_g)
3052-
if col_g is not NULL: sig_free(col_g)
3053-
raise MemoryError("Memory.")
2976+
cdef MemoryAllocator loc_mem = MemoryAllocator()
2977+
cdef int *word_g = <int *> loc_mem.malloc(self.nwords * sizeof(int))
2978+
cdef int *col_g = <int *> loc_mem.malloc(self.ncols * sizeof(int))
30542979
self.get_permutation(other, word_g, col_g)
30552980
word_l = [word_g[i] for i from 0 <= i < self.nwords]
30562981
col_l = [col_g[i] for i from 0 <= i < self.ncols]
3057-
sig_free(word_g)
3058-
sig_free(col_g)
30592982
return word_l, col_l
30602983

30612984
cdef void get_permutation(self, PartitionStack other, int *word_gamma, int *col_gamma) noexcept:
@@ -3092,80 +3015,28 @@ cdef class BinaryCodeClassifier:
30923015
self.alpha_size = self.w_gamma_size + self.radix
30933016
self.Phi_size = self.w_gamma_size/self.radix + 1
30943017

3095-
self.w_gamma = <int *> sig_malloc( self.w_gamma_size * sizeof(int) )
3096-
self.alpha = <int *> sig_malloc( self.alpha_size * sizeof(int) )
3097-
self.Phi = <unsigned int *> sig_malloc( self.Phi_size * (self.L+1) * sizeof(unsigned int) )
3098-
self.Omega = <unsigned int *> sig_malloc( self.Phi_size * self.L * sizeof(unsigned int) )
3099-
self.W = <unsigned int *> sig_malloc( self.Phi_size * self.radix * 2 * sizeof(unsigned int) )
3100-
3101-
self.base = <int *> sig_malloc( self.radix * sizeof(int) )
3102-
self.aut_gp_gens = <int *> sig_malloc( self.aut_gens_size * sizeof(int) )
3103-
self.c_gamma = <int *> sig_malloc( self.radix * sizeof(int) )
3104-
self.labeling = <int *> sig_malloc( self.radix * 3 * sizeof(int) )
3105-
self.Lambda1 = <int *> sig_malloc( self.radix * 2 * sizeof(int) )
3106-
self.Lambda2 = <int *> sig_malloc( self.radix * 2 * sizeof(int) )
3107-
self.Lambda3 = <int *> sig_malloc( self.radix * 2 * sizeof(int) )
3108-
self.v = <int *> sig_malloc( self.radix * 2 * sizeof(int) )
3109-
self.e = <int *> sig_malloc( self.radix * 2 * sizeof(int) )
3110-
3111-
if self.Phi is NULL or self.Omega is NULL or self.W is NULL or self.Lambda1 is NULL \
3112-
or self.Lambda2 is NULL or self.Lambda3 is NULL or self.w_gamma is NULL \
3113-
or self.c_gamma is NULL or self.alpha is NULL or self.v is NULL or self.e is NULL \
3114-
or self.aut_gp_gens is NULL or self.labeling is NULL or self.base is NULL:
3115-
if self.Phi is not NULL:
3116-
sig_free(self.Phi)
3117-
if self.Omega is not NULL:
3118-
sig_free(self.Omega)
3119-
if self.W is not NULL:
3120-
sig_free(self.W)
3121-
if self.Lambda1 is not NULL:
3122-
sig_free(self.Lambda1)
3123-
if self.Lambda2 is not NULL:
3124-
sig_free(self.Lambda2)
3125-
if self.Lambda3 is not NULL:
3126-
sig_free(self.Lambda3)
3127-
if self.w_gamma is not NULL:
3128-
sig_free(self.w_gamma)
3129-
if self.c_gamma is not NULL:
3130-
sig_free(self.c_gamma)
3131-
if self.alpha is not NULL:
3132-
sig_free(self.alpha)
3133-
if self.v is not NULL:
3134-
sig_free(self.v)
3135-
if self.e is not NULL:
3136-
sig_free(self.e)
3137-
if self.aut_gp_gens is not NULL:
3138-
sig_free(self.aut_gp_gens)
3139-
if self.labeling is not NULL:
3140-
sig_free(self.labeling)
3141-
if self.base is not NULL:
3142-
sig_free(self.base)
3143-
raise MemoryError("Memory.")
3144-
3145-
def __dealloc__(self):
3146-
sig_free(self.ham_wts)
3147-
sig_free(self.Phi)
3148-
sig_free(self.Omega)
3149-
sig_free(self.W)
3150-
sig_free(self.Lambda1)
3151-
sig_free(self.Lambda2)
3152-
sig_free(self.Lambda3)
3153-
sig_free(self.c_gamma)
3154-
sig_free(self.w_gamma)
3155-
sig_free(self.alpha)
3156-
sig_free(self.v)
3157-
sig_free(self.e)
3158-
sig_free(self.aut_gp_gens)
3159-
sig_free(self.labeling)
3160-
sig_free(self.base)
3018+
self.mem = MemoryAllocator()
3019+
self.w_gamma = <int *> self.mem.malloc(self.w_gamma_size * sizeof(int))
3020+
self.alpha = <int *> self.mem.malloc(self.alpha_size * sizeof(int))
3021+
self.Phi = <unsigned int *> self.mem.malloc(self.Phi_size * (self.L+1) * sizeof(unsigned int))
3022+
self.Omega = <unsigned int *> self.mem.malloc(self.Phi_size * self.L * sizeof(unsigned int))
3023+
self.W = <unsigned int *> self.mem.malloc(self.Phi_size * self.radix * 2 * sizeof(unsigned int))
3024+
3025+
self.base = <int *> self.mem.malloc(self.radix * sizeof(int))
3026+
self.aut_gp_gens = <int *> self.mem.malloc(self.aut_gens_size * sizeof(int))
3027+
self.c_gamma = <int *> self.mem.malloc(self.radix * sizeof(int))
3028+
self.labeling = <int *> self.mem.malloc(self.radix * 3 * sizeof(int))
3029+
self.Lambda1 = <int *> self.mem.malloc(self.radix * 2 * sizeof(int))
3030+
self.Lambda2 = <int *> self.mem.malloc(self.radix * 2 * sizeof(int))
3031+
self.Lambda3 = <int *> self.mem.malloc(self.radix * 2 * sizeof(int))
3032+
self.v = <int *> self.mem.malloc(self.radix * 2 * sizeof(int))
3033+
self.e = <int *> self.mem.malloc(self.radix * 2 * sizeof(int))
31613034

31623035
cdef void record_automorphism(self, int *gamma, int ncols) noexcept:
31633036
cdef int i, j
31643037
if self.aut_gp_index + ncols > self.aut_gens_size:
31653038
self.aut_gens_size *= 2
3166-
self.aut_gp_gens = <int *> sig_realloc( self.aut_gp_gens, self.aut_gens_size * sizeof(int) )
3167-
if self.aut_gp_gens is NULL:
3168-
raise MemoryError("Memory.")
3039+
self.aut_gp_gens = <int *> self.mem.realloc(self.aut_gp_gens, self.aut_gens_size * sizeof(int))
31693040
j = self.aut_gp_index
31703041
for i from 0 <= i < ncols:
31713042
self.aut_gp_gens[i+j] = gamma[i]
@@ -3404,23 +3275,12 @@ cdef class BinaryCodeClassifier:
34043275
self.w_gamma_size *= 2
34053276
self.alpha_size = self.w_gamma_size + self.radix
34063277
self.Phi_size = self.w_gamma_size/self.radix + 1
3407-
self.w_gamma = <int *> sig_realloc(self.w_gamma, self.w_gamma_size * sizeof(int))
3408-
self.alpha = <int *> sig_realloc(self.alpha, self.alpha_size * sizeof(int))
3409-
self.Phi = <unsigned int *> sig_realloc(self.Phi, self.Phi_size * self.L * sizeof(int))
3410-
self.Omega = <unsigned int *> sig_realloc(self.Omega, self.Phi_size * self.L * sizeof(int))
3411-
self.W = <unsigned int *> sig_realloc(self.W, self.Phi_size * self.radix * 2 * sizeof(int))
3412-
if self.w_gamma is NULL or self.alpha is NULL or self.Phi is NULL or self.Omega is NULL or self.W is NULL:
3413-
if self.w_gamma is not NULL:
3414-
sig_free(self.w_gamma)
3415-
if self.alpha is not NULL:
3416-
sig_free(self.alpha)
3417-
if self.Phi is not NULL:
3418-
sig_free(self.Phi)
3419-
if self.Omega is not NULL:
3420-
sig_free(self.Omega)
3421-
if self.W is not NULL:
3422-
sig_free(self.W)
3423-
raise MemoryError("Memory.")
3278+
self.w_gamma = <int *> self.mem.realloc(self.w_gamma, self.w_gamma_size * sizeof(int))
3279+
self.alpha = <int *> self.mem.realloc(self.alpha, self.alpha_size * sizeof(int))
3280+
self.Phi = <unsigned int *> self.mem.realloc(self.Phi, self.Phi_size * self.L * sizeof(int))
3281+
self.Omega = <unsigned int *> self.mem.realloc(self.Omega, self.Phi_size * self.L * sizeof(int))
3282+
self.W = <unsigned int *> self.mem.realloc(self.W, self.Phi_size * self.radix * 2 * sizeof(int))
3283+
34243284
for i from 0 <= i < self.Phi_size * self.L:
34253285
self.Omega[i] = 0
34263286
word_gamma = self.w_gamma

0 commit comments

Comments
 (0)