Skip to content

Commit

Permalink
sagemathgh-39312: use memory allocator in sage/coding/binary_code.pyx
Browse files Browse the repository at this point in the history
    
As discussed in sagemath#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,
-->
<!-- - sagemath#12345: short description why this is a dependency -->
<!-- - sagemath#34567: ... -->
    
URL: sagemath#39312
Reported by: David Coudert
Reviewer(s): David Coudert, Kwankyu Lee
  • Loading branch information
Release Manager committed Jan 15, 2025
2 parents fd3884e + 46ff10f commit 2e41329
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 194 deletions.
6 changes: 6 additions & 0 deletions src/sage/coding/binary_code.pxd
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from memory_allocator cimport MemoryAllocator

cdef int *hamming_weights() noexcept

ctypedef unsigned int codeword
Expand All @@ -11,6 +13,7 @@ cdef struct WordPermutation:
codeword gate

cdef class BinaryCode:
cdef MemoryAllocator mem
cdef codeword *basis
cdef codeword *words
cdef int ncols
Expand All @@ -34,6 +37,7 @@ cdef codeword permute_word_by_wp(WordPermutation *, codeword) noexcept
cdef codeword *expand_to_ortho_basis(BinaryCode, int) noexcept

cdef class OrbitPartition:
cdef MemoryAllocator mem
cdef int nwords
cdef int ncols
cdef int *wd_parent
Expand All @@ -52,6 +56,7 @@ cdef class OrbitPartition:
cdef int merge_perm(self, int *, int *) noexcept

cdef class PartitionStack:
cdef MemoryAllocator mem
cdef int *wd_ents
cdef int *wd_lvls
cdef int *col_ents
Expand Down Expand Up @@ -89,6 +94,7 @@ cdef class PartitionStack:
cdef void get_permutation(self, PartitionStack, int *, int *) noexcept

cdef class BinaryCodeClassifier:
cdef MemoryAllocator mem
cdef int *ham_wts
cdef int L
cdef unsigned int *Phi
Expand Down
248 changes: 54 additions & 194 deletions src/sage/coding/binary_code.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -123,8 +123,9 @@ def weight_dist(M):
cdef bitset_t word
cdef int i,j,k, dim=M.nrows(), deg=M.ncols()
cdef list L
cdef int *LL = <int *> sig_malloc((deg+1) * sizeof(int))
cdef bitset_s *basis = <bitset_s *> sig_malloc(dim * sizeof(bitset_s))
cdef MemoryAllocator mem = MemoryAllocator()
cdef int *LL = <int *> mem.malloc((deg+1) * sizeof(int))
cdef bitset_s *basis = <bitset_s *> mem.malloc(dim * sizeof(bitset_s))
for i from 0 <= i < dim:
bitset_init(&basis[i], deg)
bitset_zero(&basis[i])
Expand All @@ -150,8 +151,6 @@ def weight_dist(M):
L = [int(LL[i]) for i from 0 <= i < deg+1]
for i from 0 <= i < dim:
bitset_free(&basis[i])
sig_free(LL)
sig_free(basis)
return L


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

self.words = <codeword *> sig_malloc( nwords * sizeof(int) )
self.basis = <codeword *> sig_malloc( nrows * sizeof(int) )
if self.words is NULL or self.basis is NULL:
if self.words is not NULL: sig_free(self.words)
if self.basis is not NULL: sig_free(self.basis)
raise MemoryError("Memory.")
self.mem = MemoryAllocator()
self.words = <codeword *> self.mem.malloc(nwords * sizeof(int))
self.basis = <codeword *> self.mem.malloc(nrows * sizeof(int))
self_words = self.words
self_basis = self.basis

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

def __dealloc__(self):
sig_free(self.words)
sig_free(self.basis)

def __reduce__(self):
"""
Method for pickling and unpickling BinaryCodes.
Expand Down Expand Up @@ -1279,35 +1271,15 @@ cdef class OrbitPartition:
nwords = (1 << nrows)
self.nwords = nwords
self.ncols = ncols
self.wd_parent = <int *> sig_malloc(nwords * sizeof(int))
self.wd_rank = <int *> sig_malloc(nwords * sizeof(int))
self.wd_min_cell_rep = <int *> sig_malloc(nwords * sizeof(int))
self.wd_size = <int *> sig_malloc(nwords * sizeof(int))
self.col_parent = <int *> sig_malloc(ncols * sizeof(int))
self.col_rank = <int *> sig_malloc(ncols * sizeof(int))
self.col_min_cell_rep = <int *> sig_malloc(ncols * sizeof(int))
self.col_size = <int *> sig_malloc(ncols * sizeof(int))
if (self.wd_parent is NULL or self.wd_rank is NULL
or self.wd_min_cell_rep is NULL or self.wd_size is NULL
or self.col_parent is NULL or self.col_rank is NULL
or self.col_min_cell_rep is NULL or self.col_size is NULL):
if self.wd_parent is not NULL:
sig_free(self.wd_parent)
if self.wd_rank is not NULL:
sig_free(self.wd_rank)
if self.wd_min_cell_rep is not NULL:
sig_free(self.wd_min_cell_rep)
if self.wd_size is not NULL:
sig_free(self.wd_size)
if self.col_parent is not NULL:
sig_free(self.col_parent)
if self.col_rank is not NULL:
sig_free(self.col_rank)
if self.col_min_cell_rep is not NULL:
sig_free(self.col_min_cell_rep)
if self.col_size is not NULL:
sig_free(self.col_size)
raise MemoryError("Memory.")
self.mem = MemoryAllocator()
self.wd_parent = <int *> self.mem.malloc(nwords * sizeof(int))
self.wd_rank = <int *> self.mem.malloc(nwords * sizeof(int))
self.wd_min_cell_rep = <int *> self.mem.malloc(nwords * sizeof(int))
self.wd_size = <int *> self.mem.malloc(nwords * sizeof(int))
self.col_parent = <int *> self.mem.malloc(ncols * sizeof(int))
self.col_rank = <int *> self.mem.malloc(ncols * sizeof(int))
self.col_min_cell_rep = <int *> self.mem.malloc(ncols * sizeof(int))
self.col_size = <int *> self.mem.malloc(ncols * sizeof(int))
for word from 0 <= word < nwords:
self.wd_parent[word] = word
self.wd_rank[word] = 0
Expand All @@ -1319,16 +1291,6 @@ cdef class OrbitPartition:
self.col_min_cell_rep[col] = col
self.col_size[col] = 1

def __dealloc__(self):
sig_free(self.wd_parent)
sig_free(self.wd_rank)
sig_free(self.wd_min_cell_rep)
sig_free(self.wd_size)
sig_free(self.col_parent)
sig_free(self.col_rank)
sig_free(self.col_min_cell_rep)
sig_free(self.col_size)

def __repr__(self):
"""
Return a string representation of the orbit partition.
Expand Down Expand Up @@ -1614,44 +1576,19 @@ cdef class PartitionStack:
self.flag = (1 << (self.radix-1))

# data
self.wd_ents = <int *> sig_malloc(self.nwords * sizeof_int)
self.wd_lvls = <int *> sig_malloc(self.nwords * sizeof_int)
self.col_ents = <int *> sig_malloc(self.ncols * sizeof_int)
self.col_lvls = <int *> sig_malloc(self.ncols * sizeof_int)
self.mem = MemoryAllocator()
self.wd_ents = <int *> self.mem.malloc(self.nwords * sizeof_int)
self.wd_lvls = <int *> self.mem.malloc(self.nwords * sizeof_int)
self.col_ents = <int *> self.mem.malloc(self.ncols * sizeof_int)
self.col_lvls = <int *> self.mem.malloc(self.ncols * sizeof_int)

# scratch space
self.col_degs = <int *> sig_malloc( self.ncols * sizeof_int )
self.col_counts = <int *> sig_malloc( self.nwords * sizeof_int )
self.col_output = <int *> sig_malloc( self.ncols * sizeof_int )
self.wd_degs = <int *> sig_malloc( self.nwords * sizeof_int )
self.wd_counts = <int *> sig_malloc( (self.ncols+1) * sizeof_int )
self.wd_output = <int *> sig_malloc( self.nwords * sizeof_int )

if self.wd_ents is NULL or self.wd_lvls is NULL or self.col_ents is NULL \
or self.col_lvls is NULL or self.col_degs is NULL or self.col_counts is NULL \
or self.col_output is NULL or self.wd_degs is NULL or self.wd_counts is NULL \
or self.wd_output is NULL:
if self.wd_ents is not NULL:
sig_free(self.wd_ents)
if self.wd_lvls is not NULL:
sig_free(self.wd_lvls)
if self.col_ents is not NULL:
sig_free(self.col_ents)
if self.col_lvls is not NULL:
sig_free(self.col_lvls)
if self.col_degs is not NULL:
sig_free(self.col_degs)
if self.col_counts is not NULL:
sig_free(self.col_counts)
if self.col_output is not NULL:
sig_free(self.col_output)
if self.wd_degs is not NULL:
sig_free(self.wd_degs)
if self.wd_counts is not NULL:
sig_free(self.wd_counts)
if self.wd_output is not NULL:
sig_free(self.wd_output)
raise MemoryError("Memory.")
self.col_degs = <int *> self.mem.malloc( self.ncols * sizeof_int )
self.col_counts = <int *> self.mem.malloc( self.nwords * sizeof_int )
self.col_output = <int *> self.mem.malloc( self.ncols * sizeof_int )
self.wd_degs = <int *> self.mem.malloc( self.nwords * sizeof_int )
self.wd_counts = <int *> self.mem.malloc( (self.ncols+1) * sizeof_int )
self.wd_output = <int *> self.mem.malloc( self.nwords * sizeof_int )

nwords = self.nwords
ncols = self.ncols
Expand Down Expand Up @@ -1694,17 +1631,8 @@ cdef class PartitionStack:
wd_output[k]=0

def __dealloc__(self):
if self.basis_locations: sig_free(self.basis_locations)
sig_free(self.wd_ents)
sig_free(self.wd_lvls)
sig_free(self.col_ents)
sig_free(self.col_lvls)
sig_free(self.col_degs)
sig_free(self.col_counts)
sig_free(self.col_output)
sig_free(self.wd_degs)
sig_free(self.wd_counts)
sig_free(self.wd_output)
if self.basis_locations:
sig_free(self.basis_locations)

def print_data(self):
"""
Expand Down Expand Up @@ -3045,17 +2973,12 @@ cdef class PartitionStack:
([0, 1, 2, 3, 4, 5, 6, 7, 12, 13, 14, 15, 8, 9, 10, 11], [0, 1, 2, 3, 5, 4, 7, 6])
"""
cdef int i
cdef int *word_g = <int *> sig_malloc( self.nwords * sizeof(int) )
cdef int *col_g = <int *> sig_malloc( self.ncols * sizeof(int) )
if word_g is NULL or col_g is NULL:
if word_g is not NULL: sig_free(word_g)
if col_g is not NULL: sig_free(col_g)
raise MemoryError("Memory.")
cdef MemoryAllocator loc_mem = MemoryAllocator()
cdef int *word_g = <int *> loc_mem.malloc(self.nwords * sizeof(int))
cdef int *col_g = <int *> loc_mem.malloc(self.ncols * sizeof(int))
self.get_permutation(other, word_g, col_g)
word_l = [word_g[i] for i from 0 <= i < self.nwords]
col_l = [col_g[i] for i from 0 <= i < self.ncols]
sig_free(word_g)
sig_free(col_g)
return word_l, col_l

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

self.w_gamma = <int *> sig_malloc( self.w_gamma_size * sizeof(int) )
self.alpha = <int *> sig_malloc( self.alpha_size * sizeof(int) )
self.Phi = <unsigned int *> sig_malloc( self.Phi_size * (self.L+1) * sizeof(unsigned int) )
self.Omega = <unsigned int *> sig_malloc( self.Phi_size * self.L * sizeof(unsigned int) )
self.W = <unsigned int *> sig_malloc( self.Phi_size * self.radix * 2 * sizeof(unsigned int) )

self.base = <int *> sig_malloc( self.radix * sizeof(int) )
self.aut_gp_gens = <int *> sig_malloc( self.aut_gens_size * sizeof(int) )
self.c_gamma = <int *> sig_malloc( self.radix * sizeof(int) )
self.labeling = <int *> sig_malloc( self.radix * 3 * sizeof(int) )
self.Lambda1 = <int *> sig_malloc( self.radix * 2 * sizeof(int) )
self.Lambda2 = <int *> sig_malloc( self.radix * 2 * sizeof(int) )
self.Lambda3 = <int *> sig_malloc( self.radix * 2 * sizeof(int) )
self.v = <int *> sig_malloc( self.radix * 2 * sizeof(int) )
self.e = <int *> sig_malloc( self.radix * 2 * sizeof(int) )

if self.Phi is NULL or self.Omega is NULL or self.W is NULL or self.Lambda1 is NULL \
or self.Lambda2 is NULL or self.Lambda3 is NULL or self.w_gamma is NULL \
or self.c_gamma is NULL or self.alpha is NULL or self.v is NULL or self.e is NULL \
or self.aut_gp_gens is NULL or self.labeling is NULL or self.base is NULL:
if self.Phi is not NULL:
sig_free(self.Phi)
if self.Omega is not NULL:
sig_free(self.Omega)
if self.W is not NULL:
sig_free(self.W)
if self.Lambda1 is not NULL:
sig_free(self.Lambda1)
if self.Lambda2 is not NULL:
sig_free(self.Lambda2)
if self.Lambda3 is not NULL:
sig_free(self.Lambda3)
if self.w_gamma is not NULL:
sig_free(self.w_gamma)
if self.c_gamma is not NULL:
sig_free(self.c_gamma)
if self.alpha is not NULL:
sig_free(self.alpha)
if self.v is not NULL:
sig_free(self.v)
if self.e is not NULL:
sig_free(self.e)
if self.aut_gp_gens is not NULL:
sig_free(self.aut_gp_gens)
if self.labeling is not NULL:
sig_free(self.labeling)
if self.base is not NULL:
sig_free(self.base)
raise MemoryError("Memory.")

def __dealloc__(self):
sig_free(self.ham_wts)
sig_free(self.Phi)
sig_free(self.Omega)
sig_free(self.W)
sig_free(self.Lambda1)
sig_free(self.Lambda2)
sig_free(self.Lambda3)
sig_free(self.c_gamma)
sig_free(self.w_gamma)
sig_free(self.alpha)
sig_free(self.v)
sig_free(self.e)
sig_free(self.aut_gp_gens)
sig_free(self.labeling)
sig_free(self.base)
self.mem = MemoryAllocator()
self.w_gamma = <int *> self.mem.malloc(self.w_gamma_size * sizeof(int))
self.alpha = <int *> self.mem.malloc(self.alpha_size * sizeof(int))
self.Phi = <unsigned int *> self.mem.malloc(self.Phi_size * (self.L+1) * sizeof(unsigned int))
self.Omega = <unsigned int *> self.mem.malloc(self.Phi_size * self.L * sizeof(unsigned int))
self.W = <unsigned int *> self.mem.malloc(self.Phi_size * self.radix * 2 * sizeof(unsigned int))

self.base = <int *> self.mem.malloc(self.radix * sizeof(int))
self.aut_gp_gens = <int *> self.mem.malloc(self.aut_gens_size * sizeof(int))
self.c_gamma = <int *> self.mem.malloc(self.radix * sizeof(int))
self.labeling = <int *> self.mem.malloc(self.radix * 3 * sizeof(int))
self.Lambda1 = <int *> self.mem.malloc(self.radix * 2 * sizeof(int))
self.Lambda2 = <int *> self.mem.malloc(self.radix * 2 * sizeof(int))
self.Lambda3 = <int *> self.mem.malloc(self.radix * 2 * sizeof(int))
self.v = <int *> self.mem.malloc(self.radix * 2 * sizeof(int))
self.e = <int *> self.mem.malloc(self.radix * 2 * sizeof(int))

cdef void record_automorphism(self, int *gamma, int ncols) noexcept:
cdef int i, j
if self.aut_gp_index + ncols > self.aut_gens_size:
self.aut_gens_size *= 2
self.aut_gp_gens = <int *> sig_realloc( self.aut_gp_gens, self.aut_gens_size * sizeof(int) )
if self.aut_gp_gens is NULL:
raise MemoryError("Memory.")
self.aut_gp_gens = <int *> self.mem.realloc(self.aut_gp_gens, self.aut_gens_size * sizeof(int))
j = self.aut_gp_index
for i from 0 <= i < ncols:
self.aut_gp_gens[i+j] = gamma[i]
Expand Down Expand Up @@ -3404,23 +3275,12 @@ cdef class BinaryCodeClassifier:
self.w_gamma_size *= 2
self.alpha_size = self.w_gamma_size + self.radix
self.Phi_size = self.w_gamma_size/self.radix + 1
self.w_gamma = <int *> sig_realloc(self.w_gamma, self.w_gamma_size * sizeof(int))
self.alpha = <int *> sig_realloc(self.alpha, self.alpha_size * sizeof(int))
self.Phi = <unsigned int *> sig_realloc(self.Phi, self.Phi_size * self.L * sizeof(int))
self.Omega = <unsigned int *> sig_realloc(self.Omega, self.Phi_size * self.L * sizeof(int))
self.W = <unsigned int *> sig_realloc(self.W, self.Phi_size * self.radix * 2 * sizeof(int))
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:
if self.w_gamma is not NULL:
sig_free(self.w_gamma)
if self.alpha is not NULL:
sig_free(self.alpha)
if self.Phi is not NULL:
sig_free(self.Phi)
if self.Omega is not NULL:
sig_free(self.Omega)
if self.W is not NULL:
sig_free(self.W)
raise MemoryError("Memory.")
self.w_gamma = <int *> self.mem.realloc(self.w_gamma, self.w_gamma_size * sizeof(int))
self.alpha = <int *> self.mem.realloc(self.alpha, self.alpha_size * sizeof(int))
self.Phi = <unsigned int *> self.mem.realloc(self.Phi, self.Phi_size * self.L * sizeof(int))
self.Omega = <unsigned int *> self.mem.realloc(self.Omega, self.Phi_size * self.L * sizeof(int))
self.W = <unsigned int *> self.mem.realloc(self.W, self.Phi_size * self.radix * 2 * sizeof(int))

for i from 0 <= i < self.Phi_size * self.L:
self.Omega[i] = 0
word_gamma = self.w_gamma
Expand Down

0 comments on commit 2e41329

Please sign in to comment.