Changeset 7762:e08b43bb53cf
- Timestamp:
- 11/14/07 00:18:39 (6 years ago)
- Branch:
- default
- Location:
- sage
- Files:
-
- 3 edited
-
coding/binary_code.pxd (modified) (5 diffs)
-
coding/binary_code.pyx (modified) (11 diffs)
-
graphs/graph_isom.pyx (modified) (4 diffs)
Legend:
- Unmodified
- Added
- Removed
-
sage/coding/binary_code.pxd
r7761 r7762 16 16 17 17 cdef class OrbitPartition: 18 cdef int nwords19 18 cdef int ncols 20 cdef int *wd_parent21 cdef int *wd_rank22 cdef int *wd_min_cell_rep23 cdef int *wd_size24 19 cdef int *col_parent 25 20 cdef int *col_rank … … 27 22 cdef int *col_size 28 23 29 cdef int wd_find(self, int)30 cdef void wd_union(self, int, int)31 24 cdef int col_find(self, int) 32 25 cdef void col_union(self, int, int) 33 cdef int merge_perm(self, int * , int *)26 cdef int merge_perm(self, int *) 34 27 35 28 cdef class PartitionStack: … … 44 37 cdef int radix 45 38 cdef int flag 39 cdef int v 46 40 cdef int *col_degs # 47 41 cdef int *col_counts # … … 72 66 cdef class BinaryCodeClassifier: 73 67 cdef int *ham_wts 68 cdef int L 69 cdef int *Phi 70 cdef int *Omega 71 cdef int *W 72 cdef int radix 73 cdef int *Lambda1, *Lambda2, *Lambda3 74 cdef int *b_gamma, *c_gamma 75 cdef int *alpha 76 cdef int alpha_size 77 cdef int *v, *e 78 cdef int *aut_gp_gens, *labeling 79 cdef int aut_gp_index, aut_gens_size 80 81 cdef void record_automorphism(self, int *, int) 82 cdef void aut_gp_and_can_label(self, BinaryCode, int) 74 83 75 84 … … 80 89 81 90 82 -
sage/coding/binary_code.pyx
r7761 r7762 399 399 400 400 """ 401 def __new__(self, nrows, ncols): 402 cdef int nwords, word 401 def __new__(self, ncols): 403 402 cdef int col 404 nwords = (1 << nrows)405 self.nwords = nwords406 403 self.ncols = ncols 407 self.wd_parent = <int *> sage_malloc( nwords * sizeof(int) )408 self.wd_rank = <int *> sage_malloc( nwords * sizeof(int) )409 self.wd_min_cell_rep = <int *> sage_malloc( nwords * sizeof(int) )410 self.wd_size = <int *> sage_malloc( nwords * sizeof(int) )411 404 self.col_parent = <int *> sage_malloc( ncols * sizeof(int) ) 412 405 self.col_rank = <int *> sage_malloc( ncols * sizeof(int) ) 413 406 self.col_min_cell_rep = <int *> sage_malloc( ncols * sizeof(int) ) 414 407 self.col_size = <int *> sage_malloc( ncols * sizeof(int) ) 415 if not (self.wd_parent and self.wd_rank and self.wd_min_cell_rep and self.wd_size and self.col_parent and self.col_rank and self.col_min_cell_rep and self.col_size): 416 if self.wd_parent: sage_free(self.wd_parent) 417 if self.wd_rank: sage_free(self.wd_rank) 418 if self.wd_min_cell_rep: sage_free(self.wd_min_cell_rep) 419 if self.wd_size: sage_free(self.wd_size) 420 if self.col_parent: sage_free(self.col_parent) 421 if self.col_rank: sage_free(self.col_rank) 408 if not (self.col_parent and self.col_rank and self.col_min_cell_rep and self.col_size): 409 if self.col_parent: sage_free(self.col_parent) 410 if self.col_rank: sage_free(self.col_rank) 422 411 if self.col_min_cell_rep: sage_free(self.col_min_cell_rep) 423 if self.col_size: sage_free(self.col_size)412 if self.col_size: sage_free(self.col_size) 424 413 raise MemoryError("Memory.") 425 for word from 0 <= word < nwords:426 self.wd_parent[word] = word427 self.wd_rank[word] = 0428 self.wd_min_cell_rep[word] = word429 self.wd_size[word] = 1430 414 for col from 0 <= col < ncols: 431 415 self.col_parent[col] = col … … 435 419 436 420 def __dealloc__(self): 437 sage_free(self.wd_parent)438 sage_free(self.wd_rank)439 sage_free(self.wd_min_cell_rep)440 sage_free(self.wd_size)441 421 sage_free(self.col_parent) 442 422 sage_free(self.col_rank) … … 462 442 cdef int i 463 443 cdef int j 464 s = 'OrbitPartition on %d words and %d columns. Data:\nWords:\n'%(self.nwords, self.ncols) 465 for i from 0 <= i < self.nwords: 466 s += '%d,'%self.wd_parent[i] 444 s = 'OrbitPartition on %d columns. Data:\n'%(self.ncols) 467 445 s = s[:-1] + '\nColumns:\n' 468 446 for j from 0 <= j < self.ncols: 469 447 s += '%d,'%self.col_parent[j] 470 448 return s[:-1] 471 472 def _wd_find(self, word):473 """474 Returns the root of word.475 476 EXAMPLE:477 sage: import sage.coding.binary_code478 sage: from sage.coding.binary_code import *479 sage: O = OrbitPartition(4, 8)480 sage: O481 OrbitPartition on 16 words and 8 columns. Data:482 Words:483 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15484 Columns:485 0,1,2,3,4,5,6,7486 sage: O._wd_find(12)487 12488 489 """490 return self.wd_find(word)491 492 cdef int wd_find(self, int word):493 if self.wd_parent[word] == word:494 return word495 else:496 self.wd_parent[word] = self.wd_find(self.wd_parent[word])497 return self.wd_parent[word]498 499 def _wd_union(self, x, y):500 """501 Join the cells containing x and y.502 503 EXAMPLE:504 sage: import sage.coding.binary_code505 sage: from sage.coding.binary_code import *506 sage: O = OrbitPartition(4, 8)507 sage: O508 OrbitPartition on 16 words and 8 columns. Data:509 Words:510 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15511 Columns:512 0,1,2,3,4,5,6,7513 sage: O._wd_union(1,10)514 sage: O515 OrbitPartition on 16 words and 8 columns. Data:516 Words:517 0,1,2,3,4,5,6,7,8,9,1,11,12,13,14,15518 Columns:519 0,1,2,3,4,5,6,7520 sage: O._wd_find(10)521 1522 523 """524 self.wd_union(x, y)525 526 cdef void wd_union(self, int x, int y):527 cdef int x_root, y_root528 x_root = self.wd_find(x)529 y_root = self.wd_find(y)530 if self.wd_rank[x_root] > self.wd_rank[y_root]:531 self.wd_parent[y_root] = x_root532 self.wd_min_cell_rep[y_root] = min(self.wd_min_cell_rep[x_root],self.wd_min_cell_rep[y_root])533 self.wd_size[y_root] += self.wd_size[x_root]534 elif self.wd_rank[x_root] < self.wd_rank[y_root]:535 self.wd_parent[x_root] = y_root536 self.wd_min_cell_rep[x_root] = min(self.wd_min_cell_rep[x_root],self.wd_min_cell_rep[y_root])537 self.wd_size[x_root] += self.wd_size[y_root]538 elif x_root != y_root:539 self.wd_parent[y_root] = x_root540 self.wd_min_cell_rep[y_root] = min(self.wd_min_cell_rep[x_root],self.wd_min_cell_rep[y_root])541 self.wd_size[y_root] += self.wd_size[x_root]542 self.wd_rank[x_root] += 1543 449 544 450 def _col_find(self, col): … … 614 520 self.col_rank[x_root] += 1 615 521 616 def _merge_perm(self, col_gamma , wd_gamma):522 def _merge_perm(self, col_gamma): 617 523 """ 618 524 Merges the cells of self under the given permutation. If gamma[a] = b, … … 642 548 cdef int i 643 549 cdef int *_col_gamma 644 cdef int *_wd_gamma645 _wd_gamma = <int *> sage_malloc(self.nwords * sizeof(int))646 550 _col_gamma = <int *> sage_malloc(self.ncols * sizeof(int)) 647 if not (_col_gamma and _wd_gamma): 648 if _wd_gamma: sage_free(_wd_gamma) 649 if _col_gamma: sage_free(_col_gamma) 551 if not _col_gamma: 650 552 raise MemoryError("Memory.") 651 for i from 0 <= i < self.nwords:652 _wd_gamma[i] = wd_gamma[i]653 553 for i from 0 <= i < self.ncols: 654 554 _col_gamma[i] = col_gamma[i] 655 result = self.merge_perm(_col_gamma , _wd_gamma)555 result = self.merge_perm(_col_gamma) 656 556 sage_free(_col_gamma) 657 sage_free(_wd_gamma)658 557 return result 659 558 660 cdef int merge_perm(self, int *col_gamma , int *wd_gamma):559 cdef int merge_perm(self, int *col_gamma): 661 560 cdef int i, gamma_i_root 662 561 cdef int j, gamma_j_root, return_value = 0 663 cdef int *self_wd_parent = self.wd_parent664 562 cdef int *self_col_parent = self.col_parent 665 for i from 0 <= i < self.nwords:666 if self_wd_parent[i] == i:667 gamma_i_root = self.wd_find(wd_gamma[i])668 if gamma_i_root != i:669 return_value = 1670 self.wd_union(i, gamma_i_root)671 563 for j from 0 <= j < self.ncols: 672 564 if self_col_parent[j] == j: … … 697 589 self.nwords = other.nwords 698 590 self.ncols = other.ncols 591 699 592 self.radix = 8*sizeof(int) 700 593 self.flag = (1 << (self.radix-1)) … … 717 610 and self.col_degs and self.col_counts and self.col_output \ 718 611 and self.wd_degs and self.wd_counts and self.wd_output): 719 if self.wd_ents: sage_free(self.wd_ents)720 if self.wd_lvls: sage_free(self.wd_lvls)721 if self.col_ents: sage_free(self.col_ents)722 if self.col_lvls: sage_free(self.col_lvls)723 if self.col_degs: sage_free(self.col_degs)724 if self.col_counts: sage_free(self.col_counts)725 if self.col_output: sage_free(self.col_output)726 if self.wd_degs: sage_free(self.wd_degs)727 if self.wd_counts: sage_free(self.wd_counts)728 if self.wd_output: sage_free(self.wd_output)612 if self.wd_ents: sage_free(self.wd_ents) 613 if self.wd_lvls: sage_free(self.wd_lvls) 614 if self.col_ents: sage_free(self.col_ents) 615 if self.col_lvls: sage_free(self.col_lvls) 616 if self.col_degs: sage_free(self.col_degs) 617 if self.col_counts: sage_free(self.col_counts) 618 if self.col_output: sage_free(self.col_output) 619 if self.wd_degs: sage_free(self.wd_degs) 620 if self.wd_counts: sage_free(self.wd_counts) 621 if self.wd_output: sage_free(self.wd_output) 729 622 raise MemoryError("Memory.") 730 623 … … 1182 1075 # nontrivial cell 1183 1076 j = location 1077 self.v = j 1184 1078 while True: 1185 1079 if self_col_lvls[j] <= k: break … … 1328 1222 """ 1329 1223 Split column v out, placing it before the rest of the cell it was in. 1224 Returns the location of the split column. 1330 1225 1331 1226 EXAMPLE: … … 1789 1684 else: j = i 1790 1685 m += 1 1791 return invariant 1686 if invariant != -1: 1687 return invariant 1688 else: 1689 return 0 1792 1690 1793 1691 def _clear(self, k): … … 2094 1992 col_gamma[other_col_ents[i]] = self_col_ents[i] 2095 1993 2096 ################################################################################2097 ################################################################################2098 ################################################################################2099 2100 1994 cdef class BinaryCodeClassifier: 2101 1995 2102 1996 def __new__(self): 1997 self.radix = sizeof(int) << 3 2103 1998 self.ham_wts = hamming_weights() 1999 self.L = 100 # memory limit for Phi and Omega 2000 self.alpha_size = 65536 + self.radix 2001 self.Phi = <int *> sage_malloc( self.L * sizeof(int) ) 2002 self.Omega = <int *> sage_malloc( self.L * sizeof(int) ) 2003 self.W = <int *> sage_malloc( self.radix * sizeof(int) ) 2004 self.Lambda1 = <int *> sage_malloc( self.radix * sizeof(int) ) 2005 self.Lambda2 = <int *> sage_malloc( self.radix * sizeof(int) ) 2006 self.Lambda3 = <int *> sage_malloc( self.radix * sizeof(int) ) 2007 self.b_gamma = <int *> sage_malloc( (self.radix-1) * sizeof(int) ) 2008 self.c_gamma = <int *> sage_malloc( self.radix * sizeof(int) ) 2009 self.alpha = <int *> sage_malloc( self.alpha_size * sizeof(int) ) 2010 self.v = <int *> sage_malloc( self.radix * sizeof(int) ) 2011 self.e = <int *> sage_malloc( self.radix * sizeof(int) ) 2012 self.aut_gp_gens = <int *> sage_malloc( self.radix * 100 * sizeof(int) ) 2013 self.aut_gens_size = self.radix * 100 2014 self.labeling = <int *> sage_malloc( self.radix * sizeof(int) ) 2015 if not (self.Phi and self.Omega and self.W and self.Lambda1 and self.Lambda2 and self.Lambda3 \ 2016 and self.b_gamma and self.c_gamma and self.alpha and self.v and self.e and self.aut_gp_gens \ 2017 and self.labeling): 2018 if self.Phi: sage_free(self.Phi) 2019 if self.Omega: sage_free(self.Omega) 2020 if self.W: sage_free(self.W) 2021 if self.Lambda1: sage_free(self.Lambda1) 2022 if self.Lambda2: sage_free(self.Lambda2) 2023 if self.Lambda3: sage_free(self.Lambda3) 2024 if self.b_gamma: sage_free(self.b_gamma) 2025 if self.c_gamma: sage_free(self.c_gamma) 2026 if self.alpha: sage_free(self.alpha) 2027 if self.v: sage_free(self.v) 2028 if self.e: sage_free(self.e) 2029 if self.aut_gp_gens: sage_free(self.aut_gp_gens) 2030 if self.labeling: sage_free(self.labeling) 2031 raise MemoryError("Memory.") 2104 2032 2105 2033 def __dealloc__(self): 2106 2034 sage_free(self.ham_wts) 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 #def classify(BinaryCode C, lab=True, verbosity=0): 2127 # """ 2128 # """ 2129 # cdef int i, j # local variables 2130 # cdef OrbitPartition Theta # keeps track of which vertices have been 2131 # # discovered to be equivalent 2132 # cdef int index = 0, size = 1 2133 # cdef int L = 100 2134 # cdef int **Phi, **Omega 2135 # cdef int l = -1 2136 # cdef PartitionStack nu, zeta, rho 2137 # cdef int k_rho 2138 # cdef int k = 0 2139 # cdef int h = -1 2140 # cdef int hb 2141 # cdef int hh = 1 2142 # cdef int ht 2143 # cdef mpz_t *Lambda_mpz, *zf_mpz, *zb_mpz 2144 # cdef int hzf 2145 # cdef int hzb = -1 2146 # cdef int *basis_gamma 2147 # cdef int *col_gamma 2148 # cdef int *alpha 2149 # cdef int *v 2150 # cdef int *e 2151 # cdef int state 2152 # cdef int tvc, tvh, nwords = C.nwords, ncols = C.ncols, n = nwords + ncols, nrows = C.nrows 2153 2154 # # trivial case 2155 # if ncols == 0: 2156 # return [], {} 2157 # elif nwords == 0 and ncols == 1: 2158 # return [], {0:0} 2159 # elif nwords == 0: 2160 # output1 = [] 2161 # dd = {} 2162 # for i from 0 <= i < ncols-1: 2163 # dd[i] = i 2164 # perm = range(ncols) 2165 # perm[i] = i+1 2166 # perm[i+1] = i 2167 # output1.append(perm) 2168 # dd[ncols-1] = ncols-1 2169 # return output1, dd 2170 2171 # # allocate int pointers 2172 # Phi = <int **> sage_malloc(L * sizeof(int *)) 2173 # Omega = <int **> sage_malloc(L * sizeof(int *)) 2174 2175 # # allocate GMP int pointers 2176 # Lambda_mpz = <mpz_t *> sage_malloc((ncols+2)*sizeof(mpz_t)) 2177 # zf_mpz = <mpz_t *> sage_malloc((ncols+2)*sizeof(mpz_t)) 2178 # zb_mpz = <mpz_t *> sage_malloc((ncols+2)*sizeof(mpz_t)) 2179 2180 # # check for memory errors 2181 # if not (Phi and Omega and Lambda_mpz and zf_mpz and zb_mpz): 2182 # if Lambda_mpz: sage_free(Lambda_mpz) 2183 # if zf_mpz: sage_free(zf_mpz) 2184 # if zb_mpz: sage_free(zb_mpz) 2185 # if Phi: sage_free(Phi) 2186 # if Omega: sage_free(Omega) 2187 # raise MemoryError("Error allocating memory.") 2188 2189 # # allocate int arrays 2190 # basis_gamma = <int *> sage_malloc(nrows*sizeof(int)) 2191 # col_gamma = <int *> sage_malloc(ncols*sizeof(int)) 2192 # Phi[0] = <int *> sage_malloc(L*ncols*sizeof(int)) 2193 # Omega[0] = <int *> sage_malloc(L*ncols*sizeof(int)) 2194 # alpha = <int *> sage_malloc(4*ncols*sizeof(int)) 2195 # v = <int *> sage_malloc(ncols*sizeof(int)) 2196 # e = <int *> sage_malloc(ncols*sizeof(int)) 2197 2198 # # check for memory errors 2199 # if not (basis_gamma and col_gamma and Phi[0] and Omega[0] and alpha and v and e): 2200 # if basis_gamma: sage_free(basis_gamma) 2201 # if col_gamma: sage_free(col_gamma) 2202 # if Phi[0]: sage_free(Phi[0]) 2203 # if Omega[0]: sage_free(Omega[0]) 2204 # if alpha: sage_free(alpha) 2205 # if v: sage_free(v) 2206 # if e: sage_free(e) 2207 # sage_free(Lambda_mpz) 2208 # sage_free(zf_mpz) 2209 # sage_free(zb_mpz) 2210 # sage_free(Phi) 2211 # sage_free(Omega) 2212 # raise MemoryError("Error allocating memory.") 2213 2214 # # setup double index arrays 2215 2216 2217 2218 2219 2220 2221 2222 2223 2035 sage_free(self.Phi) 2036 sage_free(self.Omega) 2037 sage_free(self.W) 2038 sage_free(self.Lambda1) 2039 sage_free(self.Lambda2) 2040 sage_free(self.Lambda3) 2041 sage_free(self.b_gamma) 2042 sage_free(self.c_gamma) 2043 sage_free(self.alpha) 2044 sage_free(self.v) 2045 sage_free(self.e) 2046 sage_free(self.aut_gp_gens) 2047 sage_free(self.labeling) 2048 2049 cdef void record_automorphism(self, int *gamma, int ncols): 2050 cdef int i, j 2051 if self.aut_gp_index + ncols > self.aut_gens_size: 2052 self.aut_gens_size *= 2 2053 self.aut_gp_gens = <int *> sage_realloc( self.aut_gp_gens, self.aut_gens_size ) 2054 if not self.aut_gp_gens: 2055 raise MemoryError("Memory.") 2056 j = self.aut_gp_index 2057 for i from 0 <= i < ncols: 2058 self.aut_gp_gens[i+j] = gamma[i] 2059 self.aut_gp_index += ncols 2060 2061 def _aut_gp_and_can_label(self, C, verbosity=0): 2062 cdef int i, j 2063 self.aut_gp_and_can_label(C, verbosity) 2064 i = 0 2065 py_aut_gp_gens = [] 2066 while self.aut_gp_gens[i] != -1: 2067 gen = [self.aut_gp_gens[i+j] for j from 0 <= j < C.ncols] 2068 py_aut_gp_gens.append(gen) 2069 i += C.ncols 2070 py_labeling = [self.labeling[i] for i from 0 <= i < C.ncols] 2071 return py_aut_gp_gens, py_labeling 2072 2073 cdef void aut_gp_and_can_label(self, BinaryCode C, int verbosity): 2074 2075 # allocate/set up variables: 2076 cdef int i, j, ii, jj # local variables 2077 cdef OrbitPartition Theta # keeps track of which vertices have been 2078 # discovered to be equivalent 2079 cdef int index = 0, size = 1 # Define $\Gamma^{(-1)} := \text{Aut}(C)$, and 2080 # $\Gamma^{(i)} := \Gamma^{(-1)}_{v_0,...,v_i}$. 2081 # Then index = $|\Gamma^{(k-1)}|/|\Gamma^{(k)}|$ at (POINT A) 2082 # and size = $|\Gamma^{(k-1)}|$ at (POINT A) and (POINT B). 2083 cdef int *Phi = self.Phi # Phi stores the fixed point sets of each automorphism 2084 cdef int *Omega = self.Omega # Omega stores the minimal elements of each cell of the orbit partition 2085 cdef int l = -1 # current index for storing values in Phi and Omega- we start at -1 so that when 2086 # we increment first, the first place we write to is 0. 2087 cdef int *W = self.W # for each k, W[k] is a list (as int mask) of the vertices to be searched down from 2088 # the current partition, at k. Phi and Omega are ultimately used to make the size of 2089 # W as small as possible 2090 cdef PartitionStack nu, zeta, rho 2091 cdef int k_rho # the number of partitions in rho 2092 cdef int k = 0 # the number of partitions in nu 2093 cdef int h = -1 # longest common ancestor of zeta and nu: 2094 # zeta[h] == nu[h], zeta[h+1] != nu[h+1] 2095 # -1 indicates that zeta is not yet defined 2096 cdef int hb # longest common ancestor of rho and nu: 2097 # rho[hb] == nu[hb], rho[hb+1] != nu[hb+1] 2098 cdef int hh = 1 # the height of the oldest ancestor of nu 2099 # satisfying Lemma 2.25 in [1]: 2100 # if nu does not satisfy it at k, then hh = k 2101 cdef int ht # smallest such that all descendants of zeta[ht] are equivalent 2102 cdef int *Lambda = self.Lambda1 # for tracking indicator values- zf and zb are 2103 cdef int *zf__Lambda_zeta = self.Lambda2 # indicator vectors remembering Lambda[k] for 2104 cdef int *zb__Lambda_rho = self.Lambda3 # zeta and rho, respectively 2105 cdef int qzb # keeps track of Lambda[k] ><= zb[k] 2106 cdef int hzf__h_zeta # the max height for which Lambda and zf agree 2107 cdef int hzb__h_rho = -1 # the max height for which Lambda and zb agree 2108 cdef int *basis_gamma = self.b_gamma, *col_gamma = self.c_gamma # used for storing permutations 2109 cdef int tvc, tvh, nwords = C.nwords, ncols = C.ncols, nrows = C.nrows 2110 # TODO: Explain the variables tvc, tvh 2111 cdef int *alpha # for storing pointers to cells of nu[k] 2112 cdef int *v = self.v # list of vertices determining nu 2113 cdef int *e = self.e # 0 or 1, see states 12 and 17 2114 cdef int state = 1 # keeps track of position in algorithm - see sage/graphs/graph_isom.pyx, search for "STATE DIAGRAM" 2115 cdef int *ham_wts = self.ham_wts 2116 self.aut_gp_index = 0 2117 while self.alpha_size < nrows + ncols: 2118 self.alpha_size *= 2 2119 self.alpha = <int *> sage_realloc(self.alpha, self.alpha_size * sizeof(int) ) 2120 if not self.alpha: 2121 raise MemoryError("Memory.") 2122 alpha = self.alpha # think of alpha as of length exactly nrows + ncols 2123 nu = PartitionStack(nrows, ncols) 2124 Theta = OrbitPartition(ncols) 2125 2126 # trivial case 2127 if ncols == 0 or nrows == 0: 2128 raise NotImplementedError("Must supply a nontrivial code.") 2129 2130 while state != -1: 2131 2132 if state == 1: # Entry point: once only 2133 alpha[0] = 0 2134 alpha[1] = nu.flag 2135 nu.refine(k, alpha, 2, C, ham_wts) 2136 if nu.sat_225(k): hh = k 2137 if nu.is_discrete(k): state = 18; continue 2138 2139 # store the first smallest nontrivial cell in W[k], and set v[k] 2140 # equal to its minimum element 2141 W[k] = nu.first_smallest_nontrivial(k) 2142 v[k] = nu.v # stored during first_smallest_nontrivial 2143 Lambda[k] = 0 2144 e[k] = 0 2145 state = 2 2146 2147 elif state == 2: # Move down the search tree one level by refining nu: 2148 # split out a column, and refine nu against it 2149 k += 1 2150 nu.clear(k) 2151 alpha[0] = nu.split_column(v[k-1], k) 2152 Lambda[k] = nu.refine(k, alpha, 1, C, ham_wts) # store the invariant to Lambda[k] 2153 # only if this is the first time moving down the search tree: 2154 if h == -1: state = 5; continue 2155 2156 # update hzf__h_zeta 2157 if hzf__h_zeta == k-1 and Lambda[k] == zf__Lambda_zeta[k]: hzf__h_zeta = k 2158 # update qzb 2159 if zb__Lambda_rho[k] == -1 or Lambda[k] < zb__Lambda_rho[k]: 2160 qzb = -1 2161 elif Lambda[k] > zb__Lambda_rho[k]: 2162 qzb = 1 2163 else: 2164 qzb = 0 2165 # update hzb 2166 if hzb__h_rho == k-1 and qzb == 0: hzb__h_rho = k 2167 # if Lambda[k] > zb[k], then zb[k] := Lambda[k] 2168 # (zb keeps track of the indicator invariants corresponding to 2169 # rho, the closest canonical leaf so far seen- if Lambda is 2170 # bigger, then rho must be about to change 2171 if qzb > 0: zb__Lambda_rho[k] = Lambda[k] 2172 state = 3 2173 2174 elif state == 3: # attempt to rule out automorphisms while moving down the tree 2175 # if k > hzf, then we know that nu currently does not look like zeta, the first 2176 # terminal node encountered, thus there is no automorphism to discover. If qzb < 0, 2177 # i.e. Lambda[k] < zb[k], then the indicator is not maximal, and we can't reach a 2178 # canonical leaf. If neither of these is the case, then proceed to state 6. 2179 if hzf__h_zeta <= k or qzb >= 0: state = 4 2180 else: state = 6 2181 2182 elif state == 4: # at this point we have -not- ruled out the presence of automorphisms 2183 if nu.is_discrete(k): state = 7; continue # we have a terminal node, so process it 2184 2185 # otherwise, prepare to split out another column: 2186 # store the first smallest nontrivial cell in W[k], and set v[k] 2187 # equal to its minimum element 2188 W[k] = nu.first_smallest_nontrivial(k) 2189 v[k] = nu.v # stored during first_smallest_nontrivial 2190 if not nu.sat_225(k): hh = k + 1 2191 e[k] = 0 # see state 12 and 17 2192 state = 2 # continue down the tree 2193 2194 elif state == 5: # same as state 3, but in the case where we haven't yet defined zeta 2195 # i.e. this is our first time down the tree. Once we get to the bottom, 2196 # we will have zeta = nu = rho, so we do: 2197 zf__Lambda_zeta[k] = Lambda[k] 2198 zb__Lambda_rho[k] = Lambda[k] 2199 state = 4 2200 2201 elif state == 6: # at this stage, there is no reason to continue downward, so backtrack 2202 j = k 2203 # return to the longest ancestor nu[i] of nu that could have a 2204 # descendant equivalent to zeta or could improve on rho. 2205 # All terminal nodes descending from nu[hh] are known to be 2206 # equivalent, so i < hh. Also, if i > hzb, none of the 2207 # descendants of nu[i] can improve rho, since the indicator is 2208 # off (Lambda(nu) < Lambda(rho)). If i >= ht, then no descendant 2209 # of nu[i] is equivalent to zeta (see [1, p67]). 2210 if ht-1 > hzb__h_rho: 2211 if ht-1 < hh-1: 2212 k = ht-1 2213 else: 2214 k = hh-1 2215 else: 2216 if hzb__h_rho < hh-1: 2217 k = hzb__h_rho 2218 else: 2219 k = hh-1 2220 # TODO: is the following line necessary? 2221 if k == -1: k = 0 2222 # if j == hh, then all nodes lower than our current position are equivalent, so bail out 2223 if j == hh: state = 13; continue 2224 2225 # recall hh: the height of the oldest ancestor of zeta for which Lemma 2.25 is 2226 # satsified, which implies that all terminal nodes descended from there are equivalent. 2227 # If we are looking at such a node, then the partition at nu[hh] can be used for later 2228 # pruning, so we store its fixed set and a set of representatives of its cells. 2229 if l < self.L-1: l += 1 2230 Omega[l] = nu.min_cell_reps(hh) 2231 Phi[l] = nu.fixed_cols(Omega[l], hh) 2232 state = 12 2233 2234 elif state == 7: # we have just arrived at a terminal node of the search tree T(G, Pi) 2235 # if this is the first terminal node, go directly to 18, to 2236 # process zeta 2237 if h == -1: state = 18; continue 2238 2239 # hzf is the extremal height of ancestors of both nu and zeta, so if k < hzf, nu is not 2240 # equivalent to zeta, i.e. there is no automorphism to discover. 2241 if k < hzf: state = 8; continue 2242 2243 nu.get_permutation(zeta, basis_gamma, col_gamma, ham_wts) 2244 # if C^gamma == C, the permutation is an automorphism, goto 10 2245 if C.is_automorphism(col_gamma, basis_gamma): 2246 state = 10 2247 else: 2248 state = 8 2249 2250 elif state == 8: # we have just ruled out the presence of automorphism and have not yet 2251 # considered whether nu improves on rho 2252 # if qzb < 0, then rho already has larger indicator tuple 2253 if qzb < 0: state = 6; continue 2254 2255 # if Lambda[k] > zb[k] or nu is shorter than rho, then we have an improvement for rho 2256 if (qzb > 0) or (k < k_rho): state = 9; continue 2257 2258 # now Lambda[k] == zb[k] and k == k_rho, so we appeal to an enumeration: 2259 j = nu.cmp(rho, C) 2260 # if C(nu) > C(rho), we have a new label, goto 9 2261 if j > 0: state = 9; continue 2262 2263 # if C(nu) < C(rho), no new label, goto 6 2264 if j < 0: state = 6; continue 2265 2266 # if C(nu) == C(rho), get the automorphism and goto 10 2267 nu.find_basis(ham_wts) 2268 rho.get_permutation(nu, basis_gamma, col_gamma, ham_wts) 2269 state = 10 2270 2271 elif state == 9: # nu is a better guess at the canonical label than rho 2272 rho = PartitionStack(nu) 2273 k_rho = k 2274 qzb = 0 2275 hb = k 2276 hzb__h_rho = k 2277 # set zb[k+1] = Infinity 2278 zb__Lambda_rho[k+1] = -1 2279 state = 6 2280 2281 elif state == 10: # we have an automorphism to process 2282 # increment l 2283 if l < self.L-1: l += 1 2284 # store information about the automorphism to Omega and Phi 2285 # Omega stores the minimum cell representatives 2286 Omega[l] = ~0 2287 i = 0 2288 while i < ncols: 2289 j = col_gamma[i] # i is a minimum 2290 while j != i: # cell rep, 2291 Omega[l] ^= (1<<j) # so cancel 2292 j = col_gamma[j] # cellmates 2293 while i < ncols and not Omega[l]&(1<<i): # find minimal element 2294 i += 1 # of next cell 2295 # Phi stores the columns fixed by the automorphism 2296 Phi[l] = 0 2297 for i from 0 <= i < ncols: 2298 if col_gamma[i] == i: 2299 Phi[l] ^= (1 << i) 2300 # Now incorporate the automorphism into Theta 2301 j = Theta.merge_perm(col_gamma) 2302 # j stores whether anything happened or not- if not, then the automorphism we have 2303 # discovered is already in the subgroup spanned by the generators we have output 2304 if not j: state = 11; continue 2305 2306 # otherwise, we have a new generator, so record it: 2307 self.record_automorphism(col_gamma, ncols) 2308 2309 # The variable tvc was set to be the minimum element of W[k] the last time the 2310 # algorithm came up to meet zeta. At this point, we were considering the new 2311 # possibilities for descending away from zeta at this level. 2312 if Theta.col_min_cell_rep[Theta.col_find(tvc)] == tvc: 2313 # if this is still a minimum cell representative of Theta, even in light 2314 # of this new automorphism, then the current branch off of zeta hasn't been 2315 # found equivalent to one already searched yet, so there may still be a 2316 # better canonical label downward. 2317 state = 11; continue 2318 2319 # Otherwise, proceed to where zeta meets nu: 2320 k = h 2321 state = 13 2322 2323 elif state == 11: # We have just found a new automorphism, and deduced that there may 2324 # be a better canonical label below the current branch off of zeta. So go to where 2325 # nu meets rho 2326 k = hb 2327 state = 12 2328 2329 elif state == 12: # Coming here from either state 6 or 11, the algorithm has discovered 2330 # some new information. 11 came from 10, where a new line in Omega and 2331 # Phi was just recorded, and 6 stored information about implicit auto- 2332 # morphisms in Omega and Phi 2333 if e[k] == 1: 2334 # this means that the algorithm has come upward to this position (in state 17) 2335 # before, so we have already intersected W[k] with the bulk of Omega and Phi, but 2336 # we should still catch up with the latest ones 2337 W[k] &= Omega[l] 2338 state = 13 2339 2340 elif state == 13: # hub state 2341 if k == -1: state = -1; continue # exit point 2342 2343 if k > h: state = 17; continue # we are still on the same principal branch from zeta 2344 2345 if k == h: state = 14; continue # update the stabilizer index and check for new splits, 2346 # since we have returned to a partition of zeta 2347 # otherwise k < h, hence we have just backtracked up zeta, and are one level closer to done 2348 h = k 2349 tvc = 0 2350 while not (1 << tvc) & W[k]: 2351 tvc += 1 2352 # now tvc points to the minimal cell representative of W[k] 2353 state = 14 2354 2355 elif state == 14: # see if there are any more splits to make from this level of zeta (see state 17) 2356 if Theta.col_find(v[k]) == Theta.col_find(tvc): 2357 index += 1 2358 # keep tabs on how many elements are in the same cell of Theta as tvc 2359 # find the next split 2360 i = v[k] + 1 2361 while i < ncols and not (1 << i) & W[k]: 2362 i += 1 2363 if i < ncols: 2364 v[k] = i 2365 else: 2366 # there is no new split at this level 2367 v[k] = -1 2368 state = 16; continue 2369 2370 # new split column better be a minimal representative in Theta, or wasted effort 2371 if Theta.col_min_cell_rep[Theta.col_find(tvc)] == tvc: 2372 state = 15 2373 else: 2374 state = 14 2375 2376 elif state == 15: # split out the column v[k] 2377 # hh is smallest such that nu[hh] satisfies Lemma 2.25. If it is larger than k+1, 2378 # it must be modified, since we are changing that part 2379 if k + 1 < hh: 2380 hh = k + 1 2381 # hzf is maximal such that indicators line up for nu and zeta 2382 if k < hzf: 2383 hzf = k 2384 # hb is longest common ancestor of nu and rho 2385 if hb >= k: 2386 hb = k 2387 qzb = 0 2388 state = 2 2389 2390 elif state == 16: # backtrack up zeta, updating information about stabilizer vector 2391 i = W[k] 2392 j = ham_wts[i & 65535] + ham_wts[(i >> 16) & 65535] 2393 if j == index and ht == k + 1: ht = k 2394 size = size*index 2395 index = 0 2396 k -= 1 2397 state = 13 2398 2399 elif state == 17: # see if there are any more splits to make from this level of nu (and not zeta) 2400 if e[k] == 0: # now is the time to narrow down W[k] by Omega and Phi 2401 # intersect W[k] with each Omega[i] such that v[0]...v[k-1] is in Phi[i] 2402 ii = 0 2403 for i from 0 <= i < k: 2404 ii ^= (1 << v[i]) 2405 for i from 0 <= i <= l: 2406 if Phi[i] & ii == ii: 2407 W[k] &= Omega[i] 2408 e[k] = 1 2409 # see if there is a vertex to split out 2410 i = v[k] + 1 2411 while i < ncols and not (1 << i) & W[k]: 2412 i += 1 2413 if i < ncols: 2414 v[k] = i 2415 state = 15; continue 2416 2417 v[k] = -1 2418 k -= 1 2419 state = 13 2420 2421 elif state == 18: # the first time nu becomes a discrete partition: set up zeta, our "identity" leaf 2422 # initialize counters for zeta: 2423 h = k # zeta[h] == nu[h] 2424 ht = k # nodes descended from zeta[ht] are all equivalent 2425 hzf = k # max such that indicators for zeta and nu agree 2426 zeta = PartitionStack(nu) 2427 k -= 1 2428 rho = PartitionStack(nu) 2429 # initialize counters for rho: 2430 k_rho = k # number of partitions in rho 2431 hzb__h_rho = k # max such that indicators for rho and nu agree - BDM had k+1 2432 hb = k # rho[hb] == nu[hb] - BDM had k+1 2433 qzb = 0 # Lambda[k] == zb[k], so... 2434 state = 13 2435 2436 # end big while loop 2437 2438 2439 2440 -
sage/graphs/graph_isom.pyx
r7760 r7762 1211 1211 cdef int *e # 0 or 1, see states 12 and 17 1212 1212 cdef int state # keeps track of place in algorithm 1213 cdef int _dig, tv c, tvh, n = G.order()1213 cdef int _dig, tvh, n = G.order() 1214 1214 1215 1215 # trivial case … … 1607 1607 output.append([ Integer(gamma[i]) for i from 0 <= i < n ]) 1608 1608 1609 # The variable tv cwas set to be the minimum element of W[k]1609 # The variable tvh was set to be the minimum element of W[k] 1610 1610 # the last time we were at state 13 and at a node descending to 1611 1611 # zeta. If this is a minimal cell representative of Theta and … … 1614 1614 # 12, i.e. consider whether we still need to search downward from 1615 1615 # there. TODO: explain why 1616 if Theta.elements[tv c] == -1 and lab: ## added "and lab"1616 if Theta.elements[tvh] == -1 and lab: ## added "and lab" 1617 1617 state = 11 1618 1618 continue … … 1656 1656 h = k 1657 1657 1658 # set tv c and tvh to the minimum cell representative of W[k]1658 # set tvh to the minimum cell representative of W[k] 1659 1659 # (see states 10 and 14) 1660 1660 for i from 0 <= i < n: 1661 1661 if W[k][i]: 1662 tv c= i1662 tvh = i 1663 1663 break 1664 tvh = tvc1665 1664 state = 14 1666 1665
Note: See TracChangeset
for help on using the changeset viewer.
