Ticket #4115: trac_4115-double-cosets.patch
| File trac_4115-double-cosets.patch, 121.1 KB (added by rlm, 18 months ago) |
|---|
-
sage/groups/perm_gps/partn_ref/automorphism_group_canonical_label.pxd
# HG changeset patch # User Robert L. Miller <rlm@rlmiller.org> # Date 1221525292 25200 # Node ID 2df5cad14396e410bd7abf04853da22ab5f13731 # Parent 0d158c58d1c23e389772d95e77c543bfa8123446 Double coset type problems diff -r 0d158c58d1c2 -r 2df5cad14396 sage/groups/perm_gps/partn_ref/automorphism_group_canonical_label.pxd
a b 8 8 9 9 include '../../../ext/cdefs.pxi' 10 10 include '../../../ext/stdsage.pxi' 11 include ' ../../../misc/bitset_pxd.pxi'11 include 'data_structures_pxd.pxi' # includes bitsets 12 12 13 13 from sage.rings.integer cimport Integer 14 15 cdef struct OrbitPartition:16 # Disjoint set data structure for representing the orbits of the generators17 # so far found. Also keeps track of the minimum elements of the cells and18 # their sizes.19 int degree20 int *parent21 int *rank22 int *mcr # minimum cell representatives - only valid at the root of a cell23 int *size # also only valid at the root of a cell24 25 cdef inline OrbitPartition *OP_new(int)26 cdef inline int OP_dealloc(OrbitPartition *)27 cdef inline int OP_find(OrbitPartition *, int)28 cdef inline int OP_join(OrbitPartition *, int, int)29 cdef inline int OP_merge_list_perm(OrbitPartition *, int *)30 31 cdef struct PartitionStack:32 # Representation of a node of the search tree. A sequence of partitions of33 # length depth + 1, each of which is finer than the last. Partition k is34 # represented as PS.entries in order, broken up immediately after each35 # entry of levels which is at most k.36 int *entries37 int *levels38 int depth39 int degree40 41 cdef inline PartitionStack *PS_new(int, bint)42 cdef inline PartitionStack *PS_copy(PartitionStack *)43 cdef inline int PS_copy_from_to(PartitionStack *, PartitionStack *)44 cdef inline PartitionStack *PS_from_list(object)45 cdef inline int PS_dealloc(PartitionStack *)46 cdef inline int PS_print(PartitionStack *)47 cdef inline int PS_print_partition(PartitionStack *, int)48 cdef inline bint PS_is_discrete(PartitionStack *)49 cdef inline int PS_num_cells(PartitionStack *)50 cdef inline int PS_move_min_to_front(PartitionStack *, int, int)51 cdef inline bint PS_is_mcr(PartitionStack *, int)52 cdef inline bint PS_is_fixed(PartitionStack *, int)53 cdef inline int PS_clear(PartitionStack *)54 cdef inline int PS_split_point(PartitionStack *, int)55 cdef inline int PS_first_smallest(PartitionStack *, bitset_t)56 cdef inline int PS_get_perm_from(PartitionStack *, PartitionStack *, int *)57 58 cdef inline int split_point_and_refine(PartitionStack *, int, object,59 int (*)(PartitionStack *, object, int *, int), int *)60 14 61 15 cdef struct aut_gp_and_can_lab_return: 62 16 int *generators … … 69 23 cdef aut_gp_and_can_lab_return *get_aut_gp_and_can_lab( object, int **, int, 70 24 bint (*)(PartitionStack *, object), 71 25 int (*)(PartitionStack *, object, int *, int), 72 int (*)(int *, int *, object ), bint, bint, bint)26 int (*)(int *, int *, object, object), bint, bint, bint) 73 27 74 28 75 29 -
sage/groups/perm_gps/partn_ref/automorphism_group_canonical_label.pyx
diff -r 0d158c58d1c2 -r 2df5cad14396 sage/groups/perm_gps/partn_ref/automorphism_group_canonical_label.pyx
a b 58 58 59 59 Signature: 60 60 61 \code{int compare_structures(int *gamma_1, int *gamma_2, object S )}61 \code{int compare_structures(int *gamma_1, int *gamma_2, object S1, object S2)} 62 62 63 63 This function must implement a total ordering on the set of objects of fixed 64 order. Return -1 if \code{gamma_1(S ) < gamma_2(S)}, 0 if65 \code{gamma_1(S ) == gamma_2(S)}, 1 if \code{gamma_1(S) > gamma_2(S)}.64 order. Return -1 if \code{gamma_1(S1) < gamma_2(S2)}, 0 if 65 \code{gamma_1(S1) == gamma_2(S2)}, 1 if \code{gamma_1(S1) > gamma_2(S2)}. 66 66 67 67 C. \code{all_children_are_equivalent}: 68 68 … … 93 93 # http://www.gnu.org/licenses/ 94 94 #***************************************************************************** 95 95 96 include '../../../misc/bitset.pxi' 97 98 cdef inline int min(int a, int b): 99 if a < b: return a 100 else: return b 101 102 cdef inline int max(int a, int b): 103 if a > b: return a 104 else: return b 96 include 'data_structures_pyx.pxi' # includes bitsets 105 97 106 98 cdef inline int cmp(int a, int b): 107 99 if a < b: return -1 108 100 elif a == b: return 0 109 101 else: return 1 110 102 111 # OrbitPartitions112 113 cdef inline OrbitPartition *OP_new(int n):114 """115 Allocate and return a pointer to a new OrbitPartition of degree n. Returns a116 null pointer in the case of an allocation failure.117 """118 cdef int i119 cdef OrbitPartition *OP = <OrbitPartition *> \120 sage_malloc(sizeof(OrbitPartition))121 if OP is NULL:122 return OP123 OP.degree = n124 OP.parent = <int *> sage_malloc( n * sizeof(int) )125 OP.rank = <int *> sage_malloc( n * sizeof(int) )126 OP.mcr = <int *> sage_malloc( n * sizeof(int) )127 OP.size = <int *> sage_malloc( n * sizeof(int) )128 if OP.parent is NULL or OP.rank is NULL or \129 OP.mcr is NULL or OP.size is NULL:130 if OP.parent is not NULL: sage_free(OP.parent)131 if OP.rank is not NULL: sage_free(OP.rank)132 if OP.mcr is not NULL: sage_free(OP.mcr)133 if OP.size is not NULL: sage_free(OP.size)134 return NULL135 for i from 0 <= i < n:136 OP.parent[i] = i137 OP.rank[i] = 0138 OP.mcr[i] = i139 OP.size[i] = 1140 return OP141 142 cdef inline int OP_dealloc(OrbitPartition *OP):143 sage_free(OP.parent)144 sage_free(OP.rank)145 sage_free(OP.mcr)146 sage_free(OP.size)147 sage_free(OP)148 return 0149 150 cdef inline int OP_find(OrbitPartition *OP, int n):151 """152 Report the representative ("root") of the cell which contains n.153 """154 if OP.parent[n] == n:155 return n156 else:157 OP.parent[n] = OP_find(OP, OP.parent[n])158 return OP.parent[n]159 160 cdef inline int OP_join(OrbitPartition *OP, int m, int n):161 """162 Join the cells containing m and n, if they are different.163 """164 cdef int m_root = OP_find(OP, m)165 cdef int n_root = OP_find(OP, n)166 if OP.rank[m_root] > OP.rank[n_root]:167 OP.parent[n_root] = m_root168 OP.mcr[m_root] = min(OP.mcr[m_root], OP.mcr[n_root])169 OP.size[m_root] += OP.size[n_root]170 elif OP.rank[m_root] < OP.rank[n_root]:171 OP.parent[m_root] = n_root172 OP.mcr[n_root] = min(OP.mcr[m_root], OP.mcr[n_root])173 OP.size[n_root] += OP.size[m_root]174 elif m_root != n_root:175 OP.parent[n_root] = m_root176 OP.mcr[m_root] = min(OP.mcr[m_root], OP.mcr[n_root])177 OP.size[m_root] += OP.size[n_root]178 OP.rank[m_root] += 1179 180 cdef inline int OP_merge_list_perm(OrbitPartition *OP, int *gamma):181 """182 Joins the cells of OP which intersect the same orbit of gamma.183 184 INPUT:185 gamma - an integer array representing i -> gamma[i].186 187 OUTPUT:188 1 - something changed189 0 - orbits of gamma all contained in cells of OP190 """191 cdef int i, i_root, gamma_i_root, changed = 0192 for i from 0 <= i < OP.degree:193 if gamma[i] == i: continue194 i_root = OP_find(OP, i)195 gamma_i_root = OP_find(OP, gamma[i])196 if i_root != gamma_i_root:197 changed = 1198 OP_join(OP, i_root, gamma_i_root)199 return changed200 201 def OP_represent(int n=9, merges=[(0,1),(2,3),(3,4)], perm=[1,2,0,4,3,6,7,5,8]):202 """203 Demonstration and testing.204 205 DOCTEST:206 sage: from sage.groups.perm_gps.partn_ref.automorphism_group_canonical_label \207 ... import OP_represent208 sage: OP_represent()209 Allocating OrbitPartition...210 Allocation passed.211 Checking that each element reports itself as its root.212 Each element reports itself as its root.213 Merging:214 Merged 0 and 1.215 Merged 2 and 3.216 Merged 3 and 4.217 Done merging.218 Finding:219 0 -> 0, root: size=2, mcr=0, rank=1220 1 -> 0221 2 -> 2, root: size=3, mcr=2, rank=1222 3 -> 2223 4 -> 2224 5 -> 5, root: size=1, mcr=5, rank=0225 6 -> 6, root: size=1, mcr=6, rank=0226 7 -> 7, root: size=1, mcr=7, rank=0227 8 -> 8, root: size=1, mcr=8, rank=0228 Allocating array to test merge_perm.229 Allocation passed.230 Merging permutation: [1, 2, 0, 4, 3, 6, 7, 5, 8]231 Done merging.232 Finding:233 0 -> 0, root: size=5, mcr=0, rank=2234 1 -> 0235 2 -> 0236 3 -> 0237 4 -> 0238 5 -> 5, root: size=3, mcr=5, rank=1239 6 -> 5240 7 -> 5241 8 -> 8, root: size=1, mcr=8, rank=0242 Deallocating OrbitPartition.243 Done.244 245 """246 cdef int i247 print "Allocating OrbitPartition..."248 cdef OrbitPartition *OP = OP_new(n)249 if OP is NULL:250 print "Allocation failed!"251 return252 print "Allocation passed."253 print "Checking that each element reports itself as its root."254 good = True255 for i from 0 <= i < n:256 if not OP_find(OP, i) == i:257 print "Failed at i = %d!"%i258 good = False259 if good: print "Each element reports itself as its root."260 print "Merging:"261 for i,j in merges:262 OP_join(OP, i, j)263 print "Merged %d and %d."%(i,j)264 print "Done merging."265 print "Finding:"266 for i from 0 <= i < n:267 j = OP_find(OP, i)268 s = "%d -> %d"%(i, j)269 if i == j:270 s += ", root: size=%d, mcr=%d, rank=%d"%\271 (OP.size[i], OP.mcr[i], OP.rank[i])272 print s273 print "Allocating array to test merge_perm."274 cdef int *gamma = <int *> sage_malloc( n * sizeof(int) )275 if gamma is NULL:276 print "Allocation failed!"277 OP_dealloc(OP)278 return279 print "Allocation passed."280 for i from 0 <= i < n:281 gamma[i] = perm[i]282 print "Merging permutation: %s"%perm283 OP_merge_list_perm(OP, gamma)284 print "Done merging."285 print "Finding:"286 for i from 0 <= i < n:287 j = OP_find(OP, i)288 s = "%d -> %d"%(i, j)289 if i == j:290 s += ", root: size=%d, mcr=%d, rank=%d"%\291 (OP.size[i], OP.mcr[i], OP.rank[i])292 print s293 print "Deallocating OrbitPartition."294 sage_free(gamma)295 OP_dealloc(OP)296 print "Done."297 298 # PartitionStacks299 300 cdef inline PartitionStack *PS_new(int n, bint unit_partition):301 """302 Allocate and return a pointer to a new PartitionStack of degree n. Returns a303 null pointer in the case of an allocation failure.304 """305 cdef int i306 cdef PartitionStack *PS = <PartitionStack *> \307 sage_malloc(sizeof(PartitionStack))308 if PS is NULL:309 return PS310 PS.entries = <int *> sage_malloc( n * sizeof(int) )311 PS.levels = <int *> sage_malloc( n * sizeof(int) )312 if PS.entries is NULL or PS.levels is NULL:313 if PS.entries is not NULL: sage_free(PS.entries)314 if PS.levels is not NULL: sage_free(PS.levels)315 return NULL316 PS.depth = 0317 PS.degree = n318 if unit_partition:319 for i from 0 <= i < n-1:320 PS.entries[i] = i321 PS.levels[i] = n322 PS.entries[n-1] = n-1323 PS.levels[n-1] = -1324 return PS325 326 cdef inline PartitionStack *PS_copy(PartitionStack *PS):327 """328 Allocate and return a pointer to a copy of PartitionStack PS. Returns a null329 pointer in the case of an allocation failure.330 """331 cdef int i332 cdef PartitionStack *PS2 = <PartitionStack *> \333 sage_malloc(sizeof(PartitionStack))334 if PS2 is NULL:335 return PS2336 PS2.entries = <int *> sage_malloc( PS.degree * sizeof(int) )337 PS2.levels = <int *> sage_malloc( PS.degree * sizeof(int) )338 if PS2.entries is NULL or PS2.levels is NULL:339 if PS2.entries is not NULL: sage_free(PS2.entries)340 if PS2.levels is not NULL: sage_free(PS2.levels)341 return NULL342 PS_copy_from_to(PS, PS2)343 return PS2344 345 cdef inline int PS_copy_from_to(PartitionStack *PS, PartitionStack *PS2):346 """347 Copy all data from PS to PS2.348 """349 PS2.depth = PS.depth350 PS2.degree = PS.degree351 for i from 0 <= i < PS.degree:352 PS2.entries[i] = PS.entries[i]353 PS2.levels[i] = PS.levels[i]354 355 cdef inline PartitionStack *PS_from_list(object L):356 """357 Allocate and return a pointer to a PartitionStack representing L. Returns a358 null pointer in the case of an allocation failure.359 """360 cdef int cell, i, num_cells = len(L), cur_start = 0, cur_len, n = 0361 for cell from 0 <= cell < num_cells:362 n += len(L[cell])363 cdef PartitionStack *PS = PS_new(n, 0)364 cell = 0365 if PS is NULL:366 return PS367 while 1:368 cur_len = len(L[cell])369 for i from 0 <= i < cur_len:370 PS.entries[cur_start + i] = L[cell][i]371 PS.levels[cur_start + i] = n372 PS_move_min_to_front(PS, cur_start, cur_start+cur_len-1)373 cur_start += cur_len374 cell += 1375 if cell == num_cells:376 PS.levels[cur_start-1] = -1377 break378 PS.levels[cur_start-1] = 0379 return PS380 381 cdef inline int PS_dealloc(PartitionStack *PS):382 sage_free(PS.entries)383 sage_free(PS.levels)384 sage_free(PS)385 return 0386 387 cdef inline int PS_print(PartitionStack *PS):388 """389 Print a visual representation of PS.390 """391 cdef int i392 for i from 0 <= i < PS.depth + 1:393 PS_print_partition(PS, i)394 print395 396 cdef inline int PS_print_partition(PartitionStack *PS, int k):397 """398 Print the partition at depth k.399 """400 s = '('401 for i from 0 <= i < PS.degree:402 s += str(PS.entries[i])403 if PS.levels[i] <= k:404 s += '|'405 else:406 s += ','407 s = s[:-1] + ')'408 print s409 410 cdef inline bint PS_is_discrete(PartitionStack *PS):411 """412 Returns whether the deepest partition consists only of singleton cells.413 """414 cdef int i415 for i from 0 <= i < PS.degree:416 if PS.levels[i] > PS.depth:417 return 0418 return 1419 420 cdef inline int PS_num_cells(PartitionStack *PS):421 """422 Returns the number of cells.423 """424 cdef int i, ncells = 0425 for i from 0 <= i < PS.degree:426 if PS.levels[i] <= PS.depth:427 ncells += 1428 return ncells429 430 cdef inline int PS_move_min_to_front(PartitionStack *PS, int start, int end):431 """432 Makes sure that the first element of the segment of entries i with433 start <= i <= end is minimal.434 """435 cdef int i, min_loc = start, minimum = PS.entries[start]436 for i from start < i <= end:437 if PS.entries[i] < minimum:438 min_loc = i439 minimum = PS.entries[i]440 if min_loc != start:441 PS.entries[min_loc] = PS.entries[start]442 PS.entries[start] = minimum443 444 cdef inline bint PS_is_mcr(PartitionStack *PS, int m):445 """446 Returns whether PS.elements[m] (not m!) is the smallest element of its cell.447 """448 return m == 0 or PS.levels[m-1] <= PS.depth449 450 cdef inline bint PS_is_fixed(PartitionStack *PS, int m):451 """452 Returns whether PS.elements[m] (not m!) is in a singleton cell, assuming453 PS_is_mcr(PS, m) is already true.454 """455 return PS.levels[m] <= PS.depth456 457 cdef inline int PS_clear(PartitionStack *PS):458 """459 Sets the current partition to the first shallower one, i.e. forgets about460 boundaries between cells that are new to the current level.461 """462 cdef int i, cur_start = 0463 for i from 0 <= i < PS.degree:464 if PS.levels[i] >= PS.depth:465 PS.levels[i] += 1466 if PS.levels[i] < PS.depth:467 PS_move_min_to_front(PS, cur_start, i)468 cur_start = i+1469 470 cdef inline int PS_split_point(PartitionStack *PS, int v):471 """472 Detaches the point v from the cell it is in, putting the singleton cell473 of just v in front. Returns the position where v is now located.474 """475 cdef int i = 0, index_of_v476 while PS.entries[i] != v:477 i += 1478 index_of_v = i479 while PS.levels[i] > PS.depth:480 i += 1481 if (index_of_v == 0 or PS.levels[index_of_v-1] <= PS.depth) \482 and PS.levels[index_of_v] > PS.depth:483 # if v is first (make sure v is not already alone)484 PS_move_min_to_front(PS, index_of_v+1, i)485 PS.levels[index_of_v] = PS.depth486 return index_of_v487 else:488 # If v is not at front, i.e. v is not minimal in its cell,489 # then move_min_to_front is not necessary since v will swap490 # with the first before making its own cell, leaving it at491 # the front of the other.492 i = index_of_v493 while i != 0 and PS.levels[i-1] > PS.depth:494 i -= 1495 PS.entries[index_of_v] = PS.entries[i+1] # move the second element to v496 PS.entries[i+1] = PS.entries[i] # move the first (min) to second497 PS.entries[i] = v # place v first498 PS.levels[i] = PS.depth499 return i500 501 cdef inline int PS_first_smallest(PartitionStack *PS, bitset_t b):502 """503 Find the first occurrence of the smallest cell of size greater than one,504 store its entries to b, and return its minimum element.505 """506 cdef int i = 0, j = 0, location = 0, n = PS.degree507 bitset_zero(b)508 while 1:509 if PS.levels[i] <= PS.depth:510 if i != j and n > i - j + 1:511 n = i - j + 1512 location = j513 j = i + 1514 if PS.levels[i] == -1: break515 i += 1516 # location now points to the beginning of the first, smallest,517 # nontrivial cell518 i = location519 while 1:520 bitset_flip(b, PS.entries[i])521 if PS.levels[i] <= PS.depth: break522 i += 1523 return PS.entries[location]524 525 cdef inline int PS_get_perm_from(PartitionStack *PS1, PartitionStack *PS2, int *gamma):526 """527 Store the permutation determined by PS2[i] -> PS1[i] for each i, where PS[i]528 denotes the entry of the ith cell of the discrete partition PS.529 """530 cdef int i = 0531 for i from 0 <= i < PS1.degree:532 gamma[PS2.entries[i]] = PS1.entries[i]533 534 def PS_represent(partition=[[6],[3,4,8,7],[1,9,5],[0,2]], splits=[6,1,8,2]):535 """536 Demonstration and testing.537 538 DOCTEST:539 sage: from sage.groups.perm_gps.partn_ref.automorphism_group_canonical_label \540 ... import PS_represent541 sage: PS_represent()542 Allocating PartitionStack...543 Allocation passed:544 (0,1,2,3,4,5,6,7,8,9)545 Checking that entries are in order and correct level.546 Everything seems in order, deallocating.547 Deallocated.548 Creating PartitionStack from partition [[6], [3, 4, 8, 7], [1, 9, 5], [0, 2]].549 PartitionStack's data:550 entries -> [6, 3, 4, 8, 7, 1, 9, 5, 0, 2]551 levels -> [0, 10, 10, 10, 0, 10, 10, 0, 10, -1]552 depth = 0, degree = 10553 (6|3,4,8,7|1,9,5|0,2)554 Checking PS_is_discrete:555 False556 Checking PS_num_cells:557 4558 Checking PS_is_mcr, min cell reps are:559 [6, 3, 1, 0]560 Checking PS_is_fixed, fixed elements are:561 [6]562 Copying PartitionStack:563 (6|3,4,8,7|1,9,5|0,2)564 Checking for consistency.565 Everything is consistent.566 Clearing copy:567 (0,3,4,8,7,1,9,5,6,2)568 Splitting point 6 from original:569 0570 (6|3,4,8,7|1,9,5|0,2)571 Splitting point 1 from original:572 5573 (6|3,4,8,7|1|5,9|0,2)574 Splitting point 8 from original:575 1576 (6|8|3,4,7|1|5,9|0,2)577 Splitting point 2 from original:578 8579 (6|8|3,4,7|1|5,9|2|0)580 Getting permutation from PS2->PS:581 [6, 1, 0, 8, 3, 9, 2, 7, 4, 5]582 Finding first smallest:583 Minimal element is 5, bitset is:584 0000010001585 Deallocating PartitionStacks.586 Done.587 588 """589 cdef int i, n = sum([len(cell) for cell in partition]), *gamma590 cdef bitset_t b591 print "Allocating PartitionStack..."592 cdef PartitionStack *PS = PS_new(n, 1), *PS2593 if PS is NULL:594 print "Allocation failed!"595 return596 print "Allocation passed:"597 PS_print(PS)598 print "Checking that entries are in order and correct level."599 good = True600 for i from 0 <= i < n-1:601 if not (PS.entries[i] == i and PS.levels[i] == n):602 print "Failed at i = %d!"%i603 print PS.entries[i], PS.levels[i], i, n604 good = False605 if not (PS.entries[n-1] == n-1 and PS.levels[n-1] == -1):606 print "Failed at i = %d!"%(n-1)607 good = False608 if not PS.degree == n or not PS.depth == 0:609 print "Incorrect degree or depth!"610 good = False611 if good: print "Everything seems in order, deallocating."612 PS_dealloc(PS)613 print "Deallocated."614 print "Creating PartitionStack from partition %s."%partition615 PS = PS_from_list(partition)616 print "PartitionStack's data:"617 print "entries -> %s"%[PS.entries[i] for i from 0 <= i < n]618 print "levels -> %s"%[PS.levels[i] for i from 0 <= i < n]619 print "depth = %d, degree = %d"%(PS.depth,PS.degree)620 PS_print(PS)621 print "Checking PS_is_discrete:"622 print "True" if PS_is_discrete(PS) else "False"623 print "Checking PS_num_cells:"624 print PS_num_cells(PS)625 print "Checking PS_is_mcr, min cell reps are:"626 L = [PS.entries[i] for i from 0 <= i < n if PS_is_mcr(PS, i)]627 print L628 print "Checking PS_is_fixed, fixed elements are:"629 print [PS.entries[l] for l in L if PS_is_fixed(PS, l)]630 print "Copying PartitionStack:"631 PS2 = PS_copy(PS)632 PS_print(PS2)633 print "Checking for consistency."634 good = True635 for i from 0 <= i < n:636 if PS.entries[i] != PS2.entries[i] or PS.levels[i] != PS2.levels[i]:637 print "Failed at i = %d!"%i638 good = False639 if PS.degree != PS2.degree or PS.depth != PS2.depth:640 print "Failure with degree or depth!"641 good = False642 if good:643 print "Everything is consistent."644 print "Clearing copy:"645 PS_clear(PS2)646 PS_print(PS2)647 for s in splits:648 print "Splitting point %d from original:"%s649 print PS_split_point(PS, s)650 PS_print(PS)651 print "Getting permutation from PS2->PS:"652 gamma = <int *> sage_malloc(n * sizeof(int))653 PS_get_perm_from(PS, PS2, gamma)654 print [gamma[i] for i from 0 <= i < n]655 sage_free(gamma)656 print "Finding first smallest:"657 bitset_init(b, n)658 i = PS_first_smallest(PS, b)659 print "Minimal element is %d, bitset is:"%i660 print bitset_string(b)661 bitset_clear(b)662 print "Deallocating PartitionStacks."663 PS_dealloc(PS)664 PS_dealloc(PS2)665 print "Done."666 667 103 # Functions 668 669 cdef inline int split_point_and_refine(PartitionStack *PS, int v, object S,670 int (*refine_and_return_invariant)\671 (PartitionStack *PS, object S, int *cells_to_refine_by, int ctrb_len),672 int *cells_to_refine_by):673 """674 Make the partition stack one longer by copying the last partition in the675 stack, split off a given point, and refine. Return the invariant given by676 the refinement function.677 678 INPUT:679 PS -- the partition stack to refine680 v -- the point to split681 S -- the structure682 refine_and_return_invariant -- the refinement function provided683 cells_to_refine_by -- an array, contents ignored684 685 """686 PS.depth += 1687 PS_clear(PS)688 cells_to_refine_by[0] = PS_split_point(PS, v)689 return refine_and_return_invariant(PS, S, cells_to_refine_by, 1)690 104 691 105 cdef bint all_children_are_equivalent_trivial(PartitionStack *PS, object S): 692 106 return 0 … … 694 108 cdef int refine_and_return_invariant_trivial(PartitionStack *PS, object S, int *cells_to_refine_by, int ctrb_len): 695 109 return 0 696 110 697 cdef int compare_structures_trivial(int *gamma_1, int *gamma_2, object S ):111 cdef int compare_structures_trivial(int *gamma_1, int *gamma_2, object S1, object S2): 698 112 return 0 699 113 700 114 def test_get_aut_gp_and_can_lab_trivially(int n=6, partition=[[0,1,2],[3,4],[5]], … … 747 161 bint (*all_children_are_equivalent)(PartitionStack *PS, object S), 748 162 int (*refine_and_return_invariant)\ 749 163 (PartitionStack *PS, object S, int *cells_to_refine_by, int ctrb_len), 750 int (*compare_structures)(int *gamma_1, int *gamma_2, object S ),164 int (*compare_structures)(int *gamma_1, int *gamma_2, object S1, object S2), 751 165 bint canonical_label, bint base, bint order): 752 166 """ 753 167 Traverse the search space for subgroup/canonical label calculation. … … 779 193 int -- returns an invariant under application of arbitrary permutations 780 194 compare_structures -- pointer to a function 781 195 INPUT: 782 gamma_1, gamma_2 -- (list) permutations of the points of S 783 S -- pointer to the structure196 gamma_1, gamma_2 -- (list) permutations of the points of S1 and S2 197 S1, S2 -- pointers to the structures 784 198 OUTPUT: 785 int -- 0 if gamma_1(S ) = gamma_2(S), otherwise -1 or 1 (see docs for cmp),199 int -- 0 if gamma_1(S1) = gamma_2(S2), otherwise -1 or 1 (see docs for cmp), 786 200 such that the set of all structures is well-ordered 787 201 OUTPUT: 788 202 pointer to a aut_gp_and_can_lab_return struct … … 1020 434 # Ignore the invariant this time, since we are 1021 435 # creating the root of the search tree. 1022 436 refine_and_return_invariant(current_ps, S, cells_to_refine_by, j) 1023 437 PS_move_all_mins_to_front(current_ps) 438 1024 439 # Refine down to a discrete partition 1025 440 while not PS_is_discrete(current_ps): 1026 441 if not all_children_are_equivalent(current_ps, S): … … 1029 444 bitset_unset(vertices_have_been_reduced, current_ps.depth) 1030 445 i = current_ps.depth 1031 446 current_indicators[i] = split_point_and_refine(current_ps, vertices_determining_current_stack[i], S, refine_and_return_invariant, cells_to_refine_by) 447 PS_move_all_mins_to_front(current_ps) 1032 448 first_indicators[i] = current_indicators[i] 1033 449 if canonical_label: 1034 450 label_indicators[i] = current_indicators[i] … … 1074 490 bitset_flip(vertices_have_been_reduced, current_ps.depth) 1075 491 # Look for a new point to split. 1076 492 i = vertices_determining_current_stack[current_ps.depth] + 1 1077 while i < n and not bitset_check(vertices_to_split[current_ps.depth], i): 1078 i += 1 1079 if i < n: 493 i = bitset_next(vertices_to_split[current_ps.depth], i) 494 if i != -1: 1080 495 # There is a new point. 1081 496 vertices_determining_current_stack[current_ps.depth] = i 1082 497 new_vertex = 1 … … 1106 521 subgroup_primary_orbit_size += 1 1107 522 # Look for a new point to split. 1108 523 i += 1 1109 while i < n and not bitset_check(vertices_to_split[current_ps.depth], i): 1110 i += 1 1111 if i < n: 524 i = bitset_next(vertices_to_split[current_ps.depth], i) 525 if i != -1: 1112 526 # There is a new point. 1113 527 vertices_determining_current_stack[current_ps.depth] = i 1114 528 if orbits_of_subgroup.mcr[OP_find(orbits_of_subgroup, i)] == i: … … 1139 553 current_kids_are_same = current_ps.depth + 1 1140 554 if first_and_current_indicator_same > current_ps.depth: 1141 555 first_and_current_indicator_same = current_ps.depth 1142 if canonical_label and label_and_current_indicator_same > current_ps.depth:556 if canonical_label and label_and_current_indicator_same >= current_ps.depth: 1143 557 label_and_current_indicator_same = current_ps.depth 1144 558 compared_current_and_label_indicators = 0 1145 559 … … 1149 563 while 1: 1150 564 i = current_ps.depth 1151 565 current_indicators[i] = split_point_and_refine(current_ps, vertices_determining_current_stack[i], S, refine_and_return_invariant, cells_to_refine_by) 566 PS_move_all_mins_to_front(current_ps) 1152 567 if first_and_current_indicator_same == i and current_indicators[i] == first_indicators[i]: 1153 568 first_and_current_indicator_same += 1 1154 569 if canonical_label: … … 1177 592 if discrete: 1178 593 if current_ps.depth == first_and_current_indicator_same: 1179 594 PS_get_perm_from(current_ps, first_ps, permutation) 1180 if compare_structures(permutation, id_perm, S ) == 0:595 if compare_structures(permutation, id_perm, S, S) == 0: 1181 596 automorphism = 1 1182 597 if not automorphism: 1183 598 if (not canonical_label) or (compared_current_and_label_indicators < 0): … … 1188 603 if (compared_current_and_label_indicators > 0) or (current_ps.depth < label_ps.depth): 1189 604 update_label = 1 1190 605 else: 1191 i = compare_structures(current_ps.entries, label_ps.entries, S )606 i = compare_structures(current_ps.entries, label_ps.entries, S, S) 1192 607 if i > 0: 1193 608 update_label = 1 1194 609 elif i < 0: -
(a) /dev/null vs. (b) b/sage/groups/perm_gps/partn_ref/data_structures_pxd.pxi
diff -r 0d158c58d1c2 -r 2df5cad14396 sage/groups/perm_gps/partn_ref/data_structures_pxd.pxi
a b 1 2 #***************************************************************************** 3 # Copyright (C) 2006 - 2008 Robert L. Miller <rlmillster@gmail.com> 4 # 5 # Distributed under the terms of the GNU General Public License (GPL) 6 # http://www.gnu.org/licenses/ 7 #***************************************************************************** 8 9 include '../../../ext/cdefs.pxi' 10 include '../../../ext/stdsage.pxi' 11 include '../../../misc/bitset_pxd.pxi' 12 13 cdef struct OrbitPartition: 14 # Disjoint set data structure for representing the orbits of the generators 15 # so far found. Also keeps track of the minimum elements of the cells and 16 # their sizes. 17 int degree 18 int *parent 19 int *rank 20 int *mcr # minimum cell representatives - only valid at the root of a cell 21 int *size # also only valid at the root of a cell 22 23 cdef struct PartitionStack: 24 # Representation of a node of the search tree. A sequence of partitions of 25 # length depth + 1, each of which is finer than the last. Partition k is 26 # represented as PS.entries in order, broken up immediately after each 27 # entry of levels which is at most k. 28 int *entries 29 int *levels 30 int depth 31 int degree 32 33 -
(a) /dev/null vs. (b) b/sage/groups/perm_gps/partn_ref/data_structures_pyx.pxi
diff -r 0d158c58d1c2 -r 2df5cad14396 sage/groups/perm_gps/partn_ref/data_structures_pyx.pxi
a b 1 r""" 2 Data structures 3 4 This module implements TODO... 5 6 REFERENCE: 7 8 [1] McKay, Brendan D. Practical Graph Isomorphism. Congressus Numerantium, 9 Vol. 30 (1981), pp. 45-87. 10 11 """ 12 13 #***************************************************************************** 14 # Copyright (C) 2006 - 2008 Robert L. Miller <rlmillster@gmail.com> 15 # 16 # Distributed under the terms of the GNU General Public License (GPL) 17 # http://www.gnu.org/licenses/ 18 #***************************************************************************** 19 20 include '../../../misc/bitset.pxi' 21 22 cdef inline int min(int a, int b): 23 if a < b: return a 24 else: return b 25 26 cdef inline int max(int a, int b): 27 if a > b: return a 28 else: return b 29 30 # OrbitPartitions 31 32 cdef inline OrbitPartition *OP_new(int n): 33 """ 34 Allocate and return a pointer to a new OrbitPartition of degree n. Returns a 35 null pointer in the case of an allocation failure. 36 """ 37 cdef int i 38 cdef OrbitPartition *OP = <OrbitPartition *> \ 39 sage_malloc(sizeof(OrbitPartition)) 40 if OP is NULL: 41 return OP 42 OP.degree = n 43 OP.parent = <int *> sage_malloc( n * sizeof(int) ) 44 OP.rank = <int *> sage_malloc( n * sizeof(int) ) 45 OP.mcr = <int *> sage_malloc( n * sizeof(int) ) 46 OP.size = <int *> sage_malloc( n * sizeof(int) ) 47 if OP.parent is NULL or OP.rank is NULL or \ 48 OP.mcr is NULL or OP.size is NULL: 49 if OP.parent is not NULL: sage_free(OP.parent) 50 if OP.rank is not NULL: sage_free(OP.rank) 51 if OP.mcr is not NULL: sage_free(OP.mcr) 52 if OP.size is not NULL: sage_free(OP.size) 53 return NULL 54 for i from 0 <= i < n: 55 OP.parent[i] = i 56 OP.rank[i] = 0 57 OP.mcr[i] = i 58 OP.size[i] = 1 59 return OP 60 61 cdef inline int OP_dealloc(OrbitPartition *OP): 62 sage_free(OP.parent) 63 sage_free(OP.rank) 64 sage_free(OP.mcr) 65 sage_free(OP.size) 66 sage_free(OP) 67 return 0 68 69 cdef inline int OP_find(OrbitPartition *OP, int n): 70 """ 71 Report the representative ("root") of the cell which contains n. 72 """ 73 if OP.parent[n] == n: 74 return n 75 else: 76 OP.parent[n] = OP_find(OP, OP.parent[n]) 77 return OP.parent[n] 78 79 cdef inline int OP_join(OrbitPartition *OP, int m, int n): 80 """ 81 Join the cells containing m and n, if they are different. 82 """ 83 cdef int m_root = OP_find(OP, m) 84 cdef int n_root = OP_find(OP, n) 85 if OP.rank[m_root] > OP.rank[n_root]: 86 OP.parent[n_root] = m_root 87 OP.mcr[m_root] = min(OP.mcr[m_root], OP.mcr[n_root]) 88 OP.size[m_root] += OP.size[n_root] 89 elif OP.rank[m_root] < OP.rank[n_root]: 90 OP.parent[m_root] = n_root 91 OP.mcr[n_root] = min(OP.mcr[m_root], OP.mcr[n_root]) 92 OP.size[n_root] += OP.size[m_root] 93 elif m_root != n_root: 94 OP.parent[n_root] = m_root 95 OP.mcr[m_root] = min(OP.mcr[m_root], OP.mcr[n_root]) 96 OP.size[m_root] += OP.size[n_root] 97 OP.rank[m_root] += 1 98 99 cdef inline int OP_merge_list_perm(OrbitPartition *OP, int *gamma): 100 """ 101 Joins the cells of OP which intersect the same orbit of gamma. 102 103 INPUT: 104 gamma - an integer array representing i -> gamma[i]. 105 106 OUTPUT: 107 1 - something changed 108 0 - orbits of gamma all contained in cells of OP 109 """ 110 cdef int i, i_root, gamma_i_root, changed = 0 111 for i from 0 <= i < OP.degree: 112 if gamma[i] == i: continue 113 i_root = OP_find(OP, i) 114 gamma_i_root = OP_find(OP, gamma[i]) 115 if i_root != gamma_i_root: 116 changed = 1 117 OP_join(OP, i_root, gamma_i_root) 118 return changed 119 120 def OP_represent(int n=9, merges=[(0,1),(2,3),(3,4)], perm=[1,2,0,4,3,6,7,5,8]): 121 """ 122 Demonstration and testing. 123 124 DOCTEST: 125 sage: from sage.groups.perm_gps.partn_ref.automorphism_group_canonical_label \ 126 ... import OP_represent 127 sage: OP_represent() 128 Allocating OrbitPartition... 129 Allocation passed. 130 Checking that each element reports itself as its root. 131 Each element reports itself as its root. 132 Merging: 133 Merged 0 and 1. 134 Merged 2 and 3. 135 Merged 3 and 4. 136 Done merging. 137 Finding: 138 0 -> 0, root: size=2, mcr=0, rank=1 139 1 -> 0 140 2 -> 2, root: size=3, mcr=2, rank=1 141 3 -> 2 142 4 -> 2 143 5 -> 5, root: size=1, mcr=5, rank=0 144 6 -> 6, root: size=1, mcr=6, rank=0 145 7 -> 7, root: size=1, mcr=7, rank=0 146 8 -> 8, root: size=1, mcr=8, rank=0 147 Allocating array to test merge_perm. 148 Allocation passed. 149 Merging permutation: [1, 2, 0, 4, 3, 6, 7, 5, 8] 150 Done merging. 151 Finding: 152 0 -> 0, root: size=5, mcr=0, rank=2 153 1 -> 0 154 2 -> 0 155 3 -> 0 156 4 -> 0 157 5 -> 5, root: size=3, mcr=5, rank=1 158 6 -> 5 159 7 -> 5 160 8 -> 8, root: size=1, mcr=8, rank=0 161 Deallocating OrbitPartition. 162 Done. 163 164 """ 165 cdef int i 166 print "Allocating OrbitPartition..." 167 cdef OrbitPartition *OP = OP_new(n) 168 if OP is NULL: 169 print "Allocation failed!" 170 return 171 print "Allocation passed." 172 print "Checking that each element reports itself as its root." 173 good = True 174 for i from 0 <= i < n: 175 if not OP_find(OP, i) == i: 176 print "Failed at i = %d!"%i 177 good = False 178 if good: print "Each element reports itself as its root." 179 print "Merging:" 180 for i,j in merges: 181 OP_join(OP, i, j) 182 print "Merged %d and %d."%(i,j) 183 print "Done merging." 184 print "Finding:" 185 for i from 0 <= i < n: 186 j = OP_find(OP, i) 187 s = "%d -> %d"%(i, j) 188 if i == j: 189 s += ", root: size=%d, mcr=%d, rank=%d"%\ 190 (OP.size[i], OP.mcr[i], OP.rank[i]) 191 print s 192 print "Allocating array to test merge_perm." 193 cdef int *gamma = <int *> sage_malloc( n * sizeof(int) ) 194 if gamma is NULL: 195 print "Allocation failed!" 196 OP_dealloc(OP) 197 return 198 print "Allocation passed." 199 for i from 0 <= i < n: 200 gamma[i] = perm[i] 201 print "Merging permutation: %s"%perm 202 OP_merge_list_perm(OP, gamma) 203 print "Done merging." 204 print "Finding:" 205 for i from 0 <= i < n: 206 j = OP_find(OP, i) 207 s = "%d -> %d"%(i, j) 208 if i == j: 209 s += ", root: size=%d, mcr=%d, rank=%d"%\ 210 (OP.size[i], OP.mcr[i], OP.rank[i]) 211 print s 212 print "Deallocating OrbitPartition." 213 sage_free(gamma) 214 OP_dealloc(OP) 215 print "Done." 216 217 # PartitionStacks 218 219 cdef inline PartitionStack *PS_new(int n, bint unit_partition): 220 """ 221 Allocate and return a pointer to a new PartitionStack of degree n. Returns a 222 null pointer in the case of an allocation failure. 223 """ 224 cdef int i 225 cdef PartitionStack *PS = <PartitionStack *> \ 226 sage_malloc(sizeof(PartitionStack)) 227 if PS is NULL: 228 return PS 229 PS.entries = <int *> sage_malloc( n * sizeof(int) ) 230 PS.levels = <int *> sage_malloc( n * sizeof(int) ) 231 if PS.entries is NULL or PS.levels is NULL: 232 if PS.entries is not NULL: sage_free(PS.entries) 233 if PS.levels is not NULL: sage_free(PS.levels) 234 return NULL 235 PS.depth = 0 236 PS.degree = n 237 if unit_partition: 238 for i from 0 <= i < n-1: 239 PS.entries[i] = i 240 PS.levels[i] = n 241 PS.entries[n-1] = n-1 242 PS.levels[n-1] = -1 243 return PS 244 245 cdef inline PartitionStack *PS_copy(PartitionStack *PS): 246 """ 247 Allocate and return a pointer to a copy of PartitionStack PS. Returns a null 248 pointer in the case of an allocation failure. 249 """ 250 cdef int i 251 cdef PartitionStack *PS2 = <PartitionStack *> \ 252 sage_malloc(sizeof(PartitionStack)) 253 if PS2 is NULL: 254 return PS2 255 PS2.entries = <int *> sage_malloc( PS.degree * sizeof(int) ) 256 PS2.levels = <int *> sage_malloc( PS.degree * sizeof(int) ) 257 if PS2.entries is NULL or PS2.levels is NULL: 258 if PS2.entries is not NULL: sage_free(PS2.entries) 259 if PS2.levels is not NULL: sage_free(PS2.levels) 260 return NULL 261 PS_copy_from_to(PS, PS2) 262 return PS2 263 264 cdef inline int PS_copy_from_to(PartitionStack *PS, PartitionStack *PS2): 265 """ 266 Copy all data from PS to PS2. 267 """ 268 PS2.depth = PS.depth 269 PS2.degree = PS.degree 270 for i from 0 <= i < PS.degree: 271 PS2.entries[i] = PS.entries[i] 272 PS2.levels[i] = PS.levels[i] 273 274 cdef inline PartitionStack *PS_from_list(object L): 275 """ 276 Allocate and return a pointer to a PartitionStack representing L. Returns a 277 null pointer in the case of an allocation failure. 278 """ 279 cdef int cell, i, num_cells = len(L), cur_start = 0, cur_len, n = 0 280 for cell from 0 <= cell < num_cells: 281 n += len(L[cell]) 282 cdef PartitionStack *PS = PS_new(n, 0) 283 cell = 0 284 if PS is NULL: 285 return PS 286 while 1: 287 cur_len = len(L[cell]) 288 for i from 0 <= i < cur_len: 289 PS.entries[cur_start + i] = L[cell][i] 290 PS.levels[cur_start + i] = n 291 PS_move_min_to_front(PS, cur_start, cur_start+cur_len-1) 292 cur_start += cur_len 293 cell += 1 294 if cell == num_cells: 295 PS.levels[cur_start-1] = -1 296 break 297 PS.levels[cur_start-1] = 0 298 return PS 299 300 cdef inline int PS_dealloc(PartitionStack *PS): 301 sage_free(PS.entries) 302 sage_free(PS.levels) 303 sage_free(PS) 304 return 0 305 306 cdef inline int PS_print(PartitionStack *PS): 307 """ 308 Print a visual representation of PS. 309 """ 310 cdef int i 311 for i from 0 <= i < PS.depth + 1: 312 PS_print_partition(PS, i) 313 print 314 315 cdef inline int PS_print_partition(PartitionStack *PS, int k): 316 """ 317 Print the partition at depth k. 318 """ 319 s = '(' 320 for i from 0 <= i < PS.degree: 321 s += str(PS.entries[i]) 322 if PS.levels[i] <= k: 323 s += '|' 324 else: 325 s += ',' 326 s = s[:-1] + ')' 327 print s 328 329 cdef inline bint PS_is_discrete(PartitionStack *PS): 330 """ 331 Returns whether the deepest partition consists only of singleton cells. 332 """ 333 cdef int i 334 for i from 0 <= i < PS.degree: 335 if PS.levels[i] > PS.depth: 336 return 0 337 return 1 338 339 cdef inline int PS_num_cells(PartitionStack *PS): 340 """ 341 Returns the number of cells. 342 """ 343 cdef int i, ncells = 0 344 for i from 0 <= i < PS.degree: 345 if PS.levels[i] <= PS.depth: 346 ncells += 1 347 return ncells 348 349 cdef inline int PS_move_min_to_front(PartitionStack *PS, int start, int end): 350 """ 351 Makes sure that the first element of the segment of entries i with 352 start <= i <= end is minimal. 353 """ 354 cdef int i, min_loc = start, minimum = PS.entries[start] 355 for i from start < i <= end: 356 if PS.entries[i] < minimum: 357 min_loc = i 358 minimum = PS.entries[i] 359 if min_loc != start: 360 PS.entries[min_loc] = PS.entries[start] 361 PS.entries[start] = minimum 362 363 cdef inline bint PS_is_mcr(PartitionStack *PS, int m): 364 """ 365 Returns whether PS.elements[m] (not m!) is the smallest element of its cell. 366 """ 367 return m == 0 or PS.levels[m-1] <= PS.depth 368 369 cdef inline bint PS_is_fixed(PartitionStack *PS, int m): 370 """ 371 Returns whether PS.elements[m] (not m!) is in a singleton cell, assuming 372 PS_is_mcr(PS, m) is already true. 373 """ 374 return PS.levels[m] <= PS.depth 375 376 cdef inline int PS_clear(PartitionStack *PS): 377 """ 378 Sets the current partition to the first shallower one, i.e. forgets about 379 boundaries between cells that are new to the current level. 380 """ 381 cdef int i, cur_start = 0 382 for i from 0 <= i < PS.degree: 383 if PS.levels[i] >= PS.depth: 384 PS.levels[i] += 1 385 if PS.levels[i] < PS.depth: 386 PS_move_min_to_front(PS, cur_start, i) 387 cur_start = i+1 388 389 cdef inline int PS_move_all_mins_to_front(PartitionStack *PS): 390 """ 391 Move minimal cell elements to the front of each cell. 392 """ 393 cdef int i, cur_start = 0 394 for i from 0 <= i < PS.degree: 395 if PS.levels[i] <= PS.depth: 396 PS_move_min_to_front(PS, cur_start, i) 397 cur_start = i+1 398 399 cdef inline int PS_split_point(PartitionStack *PS, int v): 400 """ 401 Detaches the point v from the cell it is in, putting the singleton cell 402 of just v in front. Returns the position where v is now located. 403 """ 404 cdef int i = 0, index_of_v 405 while PS.entries[i] != v: 406 i += 1 407 index_of_v = i 408 while PS.levels[i] > PS.depth: 409 i += 1 410 if (index_of_v == 0 or PS.levels[index_of_v-1] <= PS.depth) \ 411 and PS.levels[index_of_v] > PS.depth: 412 # if v is first (make sure v is not already alone) 413 PS_move_min_to_front(PS, index_of_v+1, i) 414 PS.levels[index_of_v] = PS.depth 415 return index_of_v 416 else: 417 # If v is not at front, i.e. v is not minimal in its cell, 418 # then move_min_to_front is not necessary since v will swap 419 # with the first before making its own cell, leaving it at 420 # the front of the other. 421 i = index_of_v 422 while i != 0 and PS.levels[i-1] > PS.depth: 423 i -= 1 424 PS.entries[index_of_v] = PS.entries[i+1] # move the second element to v 425 PS.entries[i+1] = PS.entries[i] # move the first (min) to second 426 PS.entries[i] = v # place v first 427 PS.levels[i] = PS.depth 428 return i 429 430 cdef inline int PS_first_smallest(PartitionStack *PS, bitset_t b): 431 """ 432 Find the first occurrence of the smallest cell of size greater than one, 433 store its entries to b, and return its minimum element. 434 """ 435 cdef int i = 0, j = 0, location = 0, n = PS.degree 436 bitset_zero(b) 437 while 1: 438 if PS.levels[i] <= PS.depth: 439 if i != j and n > i - j + 1: 440 n = i - j + 1 441 location = j 442 j = i + 1 443 if PS.levels[i] == -1: break 444 i += 1 445 # location now points to the beginning of the first, smallest, 446 # nontrivial cell 447 i = location 448 while 1: 449 bitset_flip(b, PS.entries[i]) 450 if PS.levels[i] <= PS.depth: break 451 i += 1 452 return PS.entries[location] 453 454 cdef inline int PS_get_perm_from(PartitionStack *PS1, PartitionStack *PS2, int *gamma): 455 """ 456 Store the permutation determined by PS2[i] -> PS1[i] for each i, where PS[i] 457 denotes the entry of the ith cell of the discrete partition PS. 458 """ 459 cdef int i 460 for i from 0 <= i < PS1.degree: 461 gamma[PS2.entries[i]] = PS1.entries[i] 462 463 def PS_represent(partition=[[6],[3,4,8,7],[1,9,5],[0,2]], splits=[6,1,8,2]): 464 """ 465 Demonstration and testing. 466 467 DOCTEST: 468 sage: from sage.groups.perm_gps.partn_ref.automorphism_group_canonical_label \ 469 ... import PS_represent 470 sage: PS_represent() 471 Allocating PartitionStack... 472 Allocation passed: 473 (0,1,2,3,4,5,6,7,8,9) 474 Checking that entries are in order and correct level. 475 Everything seems in order, deallocating. 476 Deallocated. 477 Creating PartitionStack from partition [[6], [3, 4, 8, 7], [1, 9, 5], [0, 2]]. 478 PartitionStack's data: 479 entries -> [6, 3, 4, 8, 7, 1, 9, 5, 0, 2] 480 levels -> [0, 10, 10, 10, 0, 10, 10, 0, 10, -1] 481 depth = 0, degree = 10 482 (6|3,4,8,7|1,9,5|0,2) 483 Checking PS_is_discrete: 484 False 485 Checking PS_num_cells: 486 4 487 Checking PS_is_mcr, min cell reps are: 488 [6, 3, 1, 0] 489 Checking PS_is_fixed, fixed elements are: 490 [6] 491 Copying PartitionStack: 492 (6|3,4,8,7|1,9,5|0,2) 493 Checking for consistency. 494 Everything is consistent. 495 Clearing copy: 496 (0,3,4,8,7,1,9,5,6,2) 497 Splitting point 6 from original: 498 0 499 (6|3,4,8,7|1,9,5|0,2) 500 Splitting point 1 from original: 501 5 502 (6|3,4,8,7|1|5,9|0,2) 503 Splitting point 8 from original: 504 1 505 (6|8|3,4,7|1|5,9|0,2) 506 Splitting point 2 from original: 507 8 508 (6|8|3,4,7|1|5,9|2|0) 509 Getting permutation from PS2->PS: 510 [6, 1, 0, 8, 3, 9, 2, 7, 4, 5] 511 Finding first smallest: 512 Minimal element is 5, bitset is: 513 0000010001 514 Deallocating PartitionStacks. 515 Done. 516 517 """ 518 cdef int i, n = sum([len(cell) for cell in partition]), *gamma 519 cdef bitset_t b 520 print "Allocating PartitionStack..." 521 cdef PartitionStack *PS = PS_new(n, 1), *PS2 522 if PS is NULL: 523 print "Allocation failed!" 524 return 525 print "Allocation passed:" 526 PS_print(PS) 527 print "Checking that entries are in order and correct level." 528 good = True 529 for i from 0 <= i < n-1: 530 if not (PS.entries[i] == i and PS.levels[i] == n): 531 print "Failed at i = %d!"%i 532 print PS.entries[i], PS.levels[i], i, n 533 good = False 534 if not (PS.entries[n-1] == n-1 and PS.levels[n-1] == -1): 535 print "Failed at i = %d!"%(n-1) 536 good = False 537 if not PS.degree == n or not PS.depth == 0: 538 print "Incorrect degree or depth!" 539 good = False 540 if good: print "Everything seems in order, deallocating." 541 PS_dealloc(PS) 542 print "Deallocated." 543 print "Creating PartitionStack from partition %s."%partition 544 PS = PS_from_list(partition) 545 print "PartitionStack's data:" 546 print "entries -> %s"%[PS.entries[i] for i from 0 <= i < n] 547 print "levels -> %s"%[PS.levels[i] for i from 0 <= i < n] 548 print "depth = %d, degree = %d"%(PS.depth,PS.degree) 549 PS_print(PS) 550 print "Checking PS_is_discrete:" 551 print "True" if PS_is_discrete(PS) else "False" 552 print "Checking PS_num_cells:" 553 print PS_num_cells(PS) 554 print "Checking PS_is_mcr, min cell reps are:" 555 L = [PS.entries[i] for i from 0 <= i < n if PS_is_mcr(PS, i)] 556 print L 557 print "Checking PS_is_fixed, fixed elements are:" 558 print [PS.entries[l] for l in L if PS_is_fixed(PS, l)] 559 print "Copying PartitionStack:" 560 PS2 = PS_copy(PS) 561 PS_print(PS2) 562 print "Checking for consistency." 563 good = True 564 for i from 0 <= i < n: 565 if PS.entries[i] != PS2.entries[i] or PS.levels[i] != PS2.levels[i]: 566 print "Failed at i = %d!"%i 567 good = False 568 if PS.degree != PS2.degree or PS.depth != PS2.depth: 569 print "Failure with degree or depth!" 570 good = False 571 if good: 572 print "Everything is consistent." 573 print "Clearing copy:" 574 PS_clear(PS2) 575 PS_print(PS2) 576 for s in splits: 577 print "Splitting point %d from original:"%s 578 print PS_split_point(PS, s) 579 PS_print(PS) 580 print "Getting permutation from PS2->PS:" 581 gamma = <int *> sage_malloc(n * sizeof(int)) 582 PS_get_perm_from(PS, PS2, gamma) 583 print [gamma[i] for i from 0 <= i < n] 584 sage_free(gamma) 585 print "Finding first smallest:" 586 bitset_init(b, n) 587 i = PS_first_smallest(PS, b) 588 print "Minimal element is %d, bitset is:"%i 589 print bitset_string(b) 590 bitset_clear(b) 591 print "Deallocating PartitionStacks." 592 PS_dealloc(PS) 593 PS_dealloc(PS2) 594 print "Done." 595 596 # Functions 597 598 cdef inline int split_point_and_refine(PartitionStack *PS, int v, object S, 599 int (*refine_and_return_invariant)\ 600 (PartitionStack *PS, object S, int *cells_to_refine_by, int ctrb_len), 601 int *cells_to_refine_by): 602 """ 603 Make the partition stack one longer by copying the last partition in the 604 stack, split off a given point, and refine. Return the invariant given by 605 the refinement function. 606 607 INPUT: 608 PS -- the partition stack to refine 609 v -- the point to split 610 S -- the structure 611 refine_and_return_invariant -- the refinement function provided 612 cells_to_refine_by -- an array, contents ignored 613 614 """ 615 PS.depth += 1 616 PS_clear(PS) 617 cells_to_refine_by[0] = PS_split_point(PS, v) 618 return refine_and_return_invariant(PS, S, cells_to_refine_by, 1) 619 -
(a) /dev/null vs. (b) b/sage/groups/perm_gps/partn_ref/double_coset.pxd
diff -r 0d158c58d1c2 -r 2df5cad14396 sage/groups/perm_gps/partn_ref/double_coset.pxd
a b 1 2 #***************************************************************************** 3 # Copyright (C) 2006 - 2008 Robert L. Miller <rlmillster@gmail.com> 4 # 5 # Distributed under the terms of the GNU General Public License (GPL) 6 # http://www.gnu.org/licenses/ 7 #***************************************************************************** 8 9 include '../../../ext/cdefs.pxi' 10 include '../../../ext/stdsage.pxi' 11 include 'data_structures_pxd.pxi' # includes bitsets 12 13 from sage.rings.integer cimport Integer 14 15 cdef int *double_coset( object, object, int **, int *, int, 16 bint (*)(PartitionStack *, object), 17 int (*)(PartitionStack *, object, int *, int), 18 int (*)(int *, int *, object, object)) 19 20 21 -
(a) /dev/null vs. (b) b/sage/groups/perm_gps/partn_ref/double_coset.pyx
diff -r 0d158c58d1c2 -r 2df5cad14396 sage/groups/perm_gps/partn_ref/double_coset.pyx
a b 1 r""" 2 Double cosets 3 4 This module implements a general algorithm for computing double coset problems 5 for pairs of objects. The class of objects in question must be some kind 6 of structure for which an isomorphism is a permutation in $S_n$ for some $n$, 7 which we call here the order of the object. Given objects $X$ and $Y$, 8 the program returns an isomorphism in list permutation form if $X \cong Y$, and 9 a NULL pointer otherwise. 10 11 In order to take advantage of the algorithms in this module for a specific kind 12 of object, one must implement (in Cython) three functions which will be specific 13 to the kind of objects in question. Pointers to these functions are passed to 14 the main function of the module, which is \code{double_coset}. For specific 15 examples of implementations of these functions, see any of the files in 16 \code{sage.groups.perm_gps.partn_ref} beginning with "refinement." They are: 17 18 A. \code{refine_and_return_invariant}: 19 20 Signature: 21 22 \code{int refine_and_return_invariant(PartitionStack *PS, object S, int *cells_to_refine_by, int ctrb_len)} 23 24 This function should split up cells in the partition at the top of the 25 partition stack in such a way that any automorphism that respects the 26 partition also respects the resulting partition. The array 27 cells_to_refine_by is a list of the beginning positions of some cells which 28 have been changed since the last refinement. It is not necessary to use 29 this in an implementation of this function, but it will affect performance. 30 One should consult \code{refinement_graphs} for more details and ideas for 31 particular implementations. 32 33 Output: 34 35 An integer $I$ invariant under the orbits of $S_n$. That is, if 36 $\gamma \in S_n$, then 37 $$ I(G, PS, cells_to_refine_by) = I( \gamma(G), \gamma(PS), \gamma(cells_to_refine_by) ) .$$ 38 39 40 B. \code{compare_structures}: 41 42 Signature: 43 44 \code{int compare_structures(int *gamma_1, int *gamma_2, object S)} 45 46 This function must implement a total ordering on the set of objects of fixed 47 order. Return -1 if \code{gamma_1(S) < gamma_2(S)}, 0 if 48 \code{gamma_1(S) == gamma_2(S)}, 1 if \code{gamma_1(S) > gamma_2(S)}. 49 50 C. \code{all_children_are_equivalent}: 51 52 Signature: 53 54 \code{bint all_children_are_equivalent(PartitionStack *PS, object S)} 55 56 This function must return False unless it is the case that each discrete 57 partition finer than the top of the partition stack is equivalent to the 58 others under some automorphism of S. The converse need not hold: if this is 59 indeed the case, it still may return False. This function is originally used 60 as a consequence of Lemma 2.25 in [1]. 61 62 DOCTEST: 63 sage: import sage.groups.perm_gps.partn_ref.double_coset 64 65 REFERENCE: 66 67 [1] McKay, Brendan D. Practical Graph Isomorphism. Congressus Numerantium, 68 Vol. 30 (1981), pp. 45-87. 69 70 [2] Leon, Jeffrey. Permutation Group Algorithms Based on Partitions, I: 71 Theory and Algorithms. J. Symbolic Computation, Vol. 12 (1991), pp. 72 533-583. 73 74 """ 75 76 #***************************************************************************** 77 # Copyright (C) 2006 - 2008 Robert L. Miller <rlmillster@gmail.com> 78 # 79 # Distributed under the terms of the GNU General Public License (GPL) 80 # http://www.gnu.org/licenses/ 81 #***************************************************************************** 82 83 include 'data_structures_pyx.pxi' # includes bitsets 84 85 cdef inline int cmp(int a, int b): 86 if a < b: return -1 87 elif a == b: return 0 88 else: return 1 89 90 cdef inline bint stacks_are_equivalent(PartitionStack *PS1, PartitionStack *PS2): 91 cdef int i, j, depth = min(PS1.depth, PS2.depth) 92 for i from 0 <= i < PS1.degree: 93 j = cmp(PS1.levels[i], PS2.levels[i]) 94 if j == 0: continue 95 if ( (j < 0 and PS1.levels[i] <= depth and PS2.levels[i] > depth) 96 or (j > 0 and PS2.levels[i] <= depth and PS1.levels[i] > depth) ): 97 return 0 98 return 1 99 100 # Functions 101 102 cdef int *double_coset(object S1, object S2, int **partition1, int *ordering2, 103 int n, bint (*all_children_are_equivalent)(PartitionStack *PS, object S), 104 int (*refine_and_return_invariant)\ 105 (PartitionStack *PS, object S, int *cells_to_refine_by, int ctrb_len), 106 int (*compare_structures)(int *gamma_1, int *gamma_2, object S1, object S2) ): 107 """ 108 Traverse the search space for double coset calculation. 109 110 INPUT: 111 S1, S2 -- pointers to the structures 112 partition1 -- array representing a partition of the points of S1 113 ordering2 -- an ordering of the points of S2 representing a second partition 114 n -- the number of points (points are assumed to be 0,1,...,n-1) 115 all_children_are_equivalent -- pointer to a function 116 INPUT: 117 PS -- pointer to a partition stack 118 S -- pointer to the structure 119 OUTPUT: 120 bint -- returns True if it can be determined that all refinements below 121 the current one will result in an equivalent discrete partition 122 refine_and_return_invariant -- pointer to a function 123 INPUT: 124 PS -- pointer to a partition stack 125 S -- pointer to the structure 126 alpha -- an array consisting of numbers, which indicate the starting 127 positions of the cells to refine against (will likely be modified) 128 OUTPUT: 129 int -- returns an invariant under application of arbitrary permutations 130 compare_structures -- pointer to a function 131 INPUT: 132 gamma_1, gamma_2 -- (list) permutations of the points of S1 and S2 133 S1, S2 -- pointers to the structures 134 OUTPUT: 135 int -- 0 if gamma_1(S1) = gamma_2(S2), otherwise -1 or 1 (see docs for cmp), 136 such that the set of all structures is well-ordered 137 OUTPUT: 138 If S1 and S2 are isomorphic, a pointer to an integer array representing an 139 isomorphism. Otherwise, a NULL pointer. 140 141 """ 142 cdef PartitionStack *current_ps, *first_ps, *left_ps 143 cdef int first_meets_current = -1 144 cdef int current_kids_are_same = 1 145 cdef int first_kids_are_same 146 147 cdef int *indicators 148 149 cdef OrbitPartition *orbits_of_subgroup 150 cdef int subgroup_primary_orbit_size = 0 151 cdef int minimal_in_primary_orbit 152 153 cdef bitset_t *fixed_points_of_generators # i.e. fp 154 cdef bitset_t *minimal_cell_reps_of_generators # i.e. mcr 155 cdef int len_of_fp_and_mcr = 100 156 cdef int index_in_fp_and_mcr = -1 157 158 cdef bitset_t *vertices_to_split 159 cdef bitset_t vertices_have_been_reduced 160 cdef int *permutation, *id_perm, *cells_to_refine_by 161 cdef int *vertices_determining_current_stack 162 163 cdef int *output 164 165 cdef int i, j, k 166 cdef bint discrete, automorphism, update_label 167 cdef bint backtrack, new_vertex, narrow, mem_err = 0 168 169 if n == 0: 170 return NULL 171 172 indicators = <int *> sage_malloc(n * sizeof(int)) 173 174 fixed_points_of_generators = <bitset_t *> sage_malloc( len_of_fp_and_mcr * sizeof(bitset_t) ) 175 minimal_cell_reps_of_generators = <bitset_t *> sage_malloc( len_of_fp_and_mcr * sizeof(bitset_t) ) 176 177 vertices_to_split = <bitset_t *> sage_malloc( n * sizeof(bitset_t) ) 178 permutation = <int *> sage_malloc( n * sizeof(int) ) 179 id_perm = <int *> sage_malloc( n * sizeof(int) ) 180 cells_to_refine_by = <int *> sage_malloc( n * sizeof(int) ) 181 vertices_determining_current_stack = <int *> sage_malloc( n * sizeof(int) ) 182 183 output = <int *> sage_malloc( n * sizeof(int) ) 184 185 current_ps = PS_new(n, 0) 186 left_ps = PS_new(n, 0) 187 orbits_of_subgroup = OP_new(n) 188 189 # Check for allocation failures: 190 if indicators is NULL or \ 191 fixed_points_of_generators is NULL or \ 192 minimal_cell_reps_of_generators is NULL or \ 193 vertices_to_split is NULL or \ 194 permutation is NULL or \ 195 id_perm is NULL or \ 196 cells_to_refine_by is NULL or \ 197 vertices_determining_current_stack is NULL or \ 198 current_ps is NULL or \ 199 orbits_of_subgroup is NULL or \ 200 output is NULL: 201 if indicators is not NULL: 202 sage_free(indicators) 203 if fixed_points_of_generators is not NULL: 204 sage_free(fixed_points_of_generators) 205 if minimal_cell_reps_of_generators is not NULL: 206 sage_free(minimal_cell_reps_of_generators) 207 if vertices_to_split is not NULL: 208 sage_free(vertices_to_split) 209 if permutation is not NULL: 210 sage_free(permutation) 211 if id_perm is not NULL: 212 sage_free(id_perm) 213 if cells_to_refine_by is not NULL: 214 sage_free(cells_to_refine_by) 215 if vertices_determining_current_stack is not NULL: 216 sage_free(vertices_determining_current_stack) 217 if current_ps is not NULL: 218 PS_dealloc(current_ps) 219 if orbits_of_subgroup is not NULL: 220 OP_dealloc(orbits_of_subgroup) 221 if output is not NULL: 222 sage_free(output) 223 raise MemoryError 224 225 # Initialize bitsets, checking for allocation failures: 226 cdef bint succeeded = 1 227 for i from 0 <= i < len_of_fp_and_mcr: 228 try: 229 bitset_init(fixed_points_of_generators[i], n) 230 except MemoryError: 231 succeeded = 0 232 for j from 0 <= j < i: 233 bitset_clear(fixed_points_of_generators[j]) 234 bitset_clear(minimal_cell_reps_of_generators[j]) 235 break 236 try: 237 bitset_init(minimal_cell_reps_of_generators[i], n) 238 except MemoryError: 239 succeeded = 0 240 for j from 0 <= j < i: 241 bitset_clear(fixed_points_of_generators[j]) 242 bitset_clear(minimal_cell_reps_of_generators[j]) 243 bitset_clear(fixed_points_of_generators[i]) 244 break 245 if succeeded: 246 for i from 0 <= i < n: 247 try: 248 bitset_init(vertices_to_split[i], n) 249 except MemoryError: 250 succeeded = 0 251 for j from 0 <= j < i: 252 bitset_clear(vertices_to_split[j]) 253 for j from 0 <= j < len_of_fp_and_mcr: 254 bitset_clear(fixed_points_of_generators[j]) 255 bitset_clear(minimal_cell_reps_of_generators[j]) 256 break 257 if succeeded: 258 try: 259 bitset_init(vertices_have_been_reduced, n) 260 except MemoryError: 261 succeeded = 0 262 for j from 0 <= j < n: 263 bitset_clear(vertices_to_split[j]) 264 for j from 0 <= j < len_of_fp_and_mcr: 265 bitset_clear(fixed_points_of_generators[j]) 266 bitset_clear(minimal_cell_reps_of_generators[j]) 267 if not succeeded: 268 sage_free(indicators) 269 sage_free(fixed_points_of_generators) 270 sage_free(minimal_cell_reps_of_generators) 271 sage_free(vertices_to_split) 272 sage_free(permutation) 273 sage_free(id_perm) 274 sage_free(cells_to_refine_by) 275 sage_free(vertices_determining_current_stack) 276 PS_dealloc(current_ps) 277 PS_dealloc(left_ps) 278 OP_dealloc(orbits_of_subgroup) 279 raise MemoryError 280 281 bitset_zero(vertices_have_been_reduced) 282 283 # set up the identity permutation 284 for i from 0 <= i < n: 285 id_perm[i] = i 286 if ordering2 is NULL: 287 ordering2 = id_perm 288 289 # Copy data of partition to left_ps, and 290 # ordering of that partition to current_ps. 291 i = 0 292 j = 0 293 while partition1[i] is not NULL: 294 k = 0 295 while partition1[i][k] != -1: 296 left_ps.entries[j+k] = partition1[i][k] 297 left_ps.levels[j+k] = n 298 current_ps.entries[j+k] = ordering2[j+k] 299 current_ps.levels[j+k] = n 300 k += 1 301 left_ps.levels[j+k-1] = 0 302 current_ps.levels[j+k-1] = 0 303 PS_move_min_to_front(current_ps, j, j+k-1) 304 j += k 305 i += 1 306 left_ps.levels[j-1] = -1 307 current_ps.levels[j-1] = -1 308 left_ps.depth = 0 309 current_ps.depth = 0 310 left_ps.degree = n 311 current_ps.degree = n 312 313 # default values of "infinity" 314 for i from 0 <= i < n: 315 indicators[i] = -1 316 317 cdef bint possible = 1 318 cdef bint unknown = 1 319 320 # Our first refinement needs to check every cell of the partition, 321 # so cells_to_refine_by needs to be a list of pointers to each cell. 322 j = 1 323 cells_to_refine_by[0] = 0 324 for i from 0 < i < n: 325 if left_ps.levels[i-1] == 0: 326 cells_to_refine_by[j] = i 327 j += 1 328 329 k = refine_and_return_invariant(left_ps, S1, cells_to_refine_by, j) 330 331 j = 1 332 cells_to_refine_by[0] = 0 333 for i from 0 < i < n: 334 if current_ps.levels[i-1] == 0: 335 cells_to_refine_by[j] = i 336 j += 1 337 j = refine_and_return_invariant(current_ps, S2, cells_to_refine_by, j) 338 if k != j: 339 possible = 0; unknown = 0 340 elif not stacks_are_equivalent(left_ps, current_ps): 341 possible = 0; unknown = 0 342 else: 343 PS_move_all_mins_to_front(current_ps) 344 345 first_ps = NULL 346 # Refine down to a discrete partition 347 while not PS_is_discrete(left_ps) and possible: 348 k = PS_first_smallest(left_ps, vertices_to_split[left_ps.depth]) 349 i = left_ps.depth 350 indicators[i] = split_point_and_refine(left_ps, k, S1, refine_and_return_invariant, cells_to_refine_by) 351 vertices_determining_current_stack[current_ps.depth] = PS_first_smallest(current_ps, vertices_to_split[current_ps.depth]) 352 bitset_unset(vertices_have_been_reduced, current_ps.depth) 353 while 1: 354 j = split_point_and_refine(current_ps, vertices_determining_current_stack[i], S2, refine_and_return_invariant, cells_to_refine_by) 355 if indicators[i] != j: 356 possible = 0 357 elif not stacks_are_equivalent(left_ps, current_ps): 358 possible = 0 359 else: 360 PS_move_all_mins_to_front(current_ps) 361 if not possible: 362 j = vertices_determining_current_stack[i] + 1 363 j = bitset_next(vertices_to_split[i], j) 364 if j == -1: 365 break 366 else: 367 possible = 1 368 vertices_determining_current_stack[i] = j 369 current_ps.depth -= 1 # reset for next refinement 370 else: break 371 if not all_children_are_equivalent(current_ps, S2): 372 current_kids_are_same = current_ps.depth + 1 373 374 if possible: 375 if compare_structures(left_ps.entries, current_ps.entries, S1, S2) == 0: 376 unknown = 0 377 else: 378 first_meets_current = current_ps.depth 379 first_kids_are_same = current_ps.depth 380 first_ps = PS_copy(current_ps) 381 current_ps.depth -= 1 382 383 # Main loop: 384 while possible and unknown and current_ps.depth != -1: 385 386 # I. Search for a new vertex to split, and update subgroup information 387 new_vertex = 0 388 if current_ps.depth > first_meets_current: 389 # If we are not at a node of the first stack, reduce size of 390 # vertices_to_split by using the symmetries we already know. 391 if not bitset_check(vertices_have_been_reduced, current_ps.depth): 392 for i from 0 <= i <= index_in_fp_and_mcr: 393 j = 0 394 while j < current_ps.depth and bitset_check(fixed_points_of_generators[i], vertices_determining_current_stack[j]): 395 j += 1 396 # If each vertex split so far is fixed by generator i, 397 # then remove elements of vertices_to_split which are 398 # not minimal in their orbits under generator i. 399 if j == current_ps.depth: 400 for k from 0 <= k < n: 401 if bitset_check(vertices_to_split[current_ps.depth], k) and not bitset_check(minimal_cell_reps_of_generators[i], k): 402 bitset_flip(vertices_to_split[current_ps.depth], k) 403 bitset_flip(vertices_have_been_reduced, current_ps.depth) 404 # Look for a new point to split. 405 i = vertices_determining_current_stack[current_ps.depth] + 1 406 i = bitset_next(vertices_to_split[current_ps.depth], i) 407 if i != -1: 408 # There is a new point. 409 vertices_determining_current_stack[current_ps.depth] = i 410 new_vertex = 1 411 else: 412 # No new point: backtrack. 413 current_ps.depth -= 1 414 else: 415 # If we are at a node of the first stack, the above reduction 416 # will not help. Also, we must update information about 417 # primary orbits here. 418 if current_ps.depth < first_meets_current: 419 # If we are done searching under this part of the first 420 # stack, then first_meets_current is one higher, and we 421 # are looking at a new primary orbit (corresponding to a 422 # larger subgroup in the stabilizer chain). 423 first_meets_current = current_ps.depth 424 for i from 0 <= i < n: 425 if bitset_check(vertices_to_split[current_ps.depth], i): 426 minimal_in_primary_orbit = i 427 break 428 while 1: 429 i = vertices_determining_current_stack[current_ps.depth] 430 # This was the last point to be split here. 431 # If it is in the same orbit as minimal_in_primary_orbit, 432 # then count it as an element of the primary orbit. 433 if OP_find(orbits_of_subgroup, i) == OP_find(orbits_of_subgroup, minimal_in_primary_orbit): 434 subgroup_primary_orbit_size += 1 435 # Look for a new point to split. 436 i += 1 437 i = bitset_next(vertices_to_split[current_ps.depth], i) 438 if i != -1: 439 # There is a new point. 440 vertices_determining_current_stack[current_ps.depth] = i 441 if orbits_of_subgroup.mcr[OP_find(orbits_of_subgroup, i)] == i: 442 new_vertex = 1 443 break 444 else: 445 # No new point: backtrack. 446 # Note that now, we are backtracking up the first stack. 447 vertices_determining_current_stack[current_ps.depth] = -1 448 # If every choice of point to split gave something in the 449 # (same!) primary orbit, then all children of the first 450 # stack at this point are equivalent. 451 j = 0 452 for i from 0 <= i < n: 453 if bitset_check(vertices_to_split[current_ps.depth], i): 454 j += 1 455 if j == subgroup_primary_orbit_size and first_kids_are_same == current_ps.depth+1: 456 first_kids_are_same = current_ps.depth 457 # Backtrack. 458 subgroup_primary_orbit_size = 0 459 current_ps.depth -= 1 460 break 461 if not new_vertex: 462 continue 463 464 if current_kids_are_same > current_ps.depth + 1: 465 current_kids_are_same = current_ps.depth + 1 466 467 # II. Refine down to a discrete partition, or until 468 # we leave the part of the tree we are interested in 469 discrete = 0 470 while 1: 471 i = current_ps.depth 472 while 1: 473 k = split_point_and_refine(current_ps, vertices_determining_current_stack[i], S2, refine_and_return_invariant, cells_to_refine_by) 474 PS_move_all_mins_to_front(current_ps) 475 if indicators[i] != k: 476 possible = 0 477 elif not stacks_are_equivalent(left_ps, current_ps): 478 possible = 0 479 if not possible: 480 j = vertices_determining_current_stack[i] + 1 481 j = bitset_next(vertices_to_split[i], j) 482 if j == -1: 483 break 484 else: 485 possible = 1 486 vertices_determining_current_stack[i] = j 487 current_ps.depth -= 1 # reset for next refinement 488 else: break 489 if not possible: 490 break 491 if PS_is_discrete(current_ps): 492 break 493 vertices_determining_current_stack[current_ps.depth] = PS_first_smallest(current_ps, vertices_to_split[current_ps.depth]) 494 bitset_unset(vertices_have_been_reduced, current_ps.depth) 495 if not all_children_are_equivalent(current_ps, S2): 496 current_kids_are_same = current_ps.depth + 1 497 498 # III. Check for automorphisms and isomorphisms 499 automorphism = 0 500 if possible: 501 PS_get_perm_from(current_ps, first_ps, permutation) 502 if compare_structures(permutation, id_perm, S2, S2) == 0: 503 automorphism = 1 504 if not automorphism and possible: 505 # if we get here, discrete must be true 506 if current_ps.depth != left_ps.depth: 507 possible = 0 508 elif compare_structures(left_ps.entries, current_ps.entries, S1, S2) == 0: 509 unknown = 0 510 break # main loop 511 else: 512 possible = 0 513 if automorphism: 514 if index_in_fp_and_mcr < len_of_fp_and_mcr - 1: 515 index_in_fp_and_mcr += 1 516 bitset_zero(fixed_points_of_generators[index_in_fp_and_mcr]) 517 bitset_zero(minimal_cell_reps_of_generators[index_in_fp_and_mcr]) 518 for i from 0 <= i < n: 519 if permutation[i] == i: 520 bitset_set(fixed_points_of_generators[index_in_fp_and_mcr], i) 521 bitset_set(minimal_cell_reps_of_generators[index_in_fp_and_mcr], i) 522 else: 523 bitset_unset(fixed_points_of_generators[index_in_fp_and_mcr], i) 524 k = i 525 j = permutation[i] 526 while j != i: 527 if j < k: k = j 528 j = permutation[j] 529 if k == i: 530 bitset_set(minimal_cell_reps_of_generators[index_in_fp_and_mcr], i) 531 else: 532 bitset_unset(minimal_cell_reps_of_generators[index_in_fp_and_mcr], i) 533 current_ps.depth = first_meets_current 534 if OP_merge_list_perm(orbits_of_subgroup, permutation): # if permutation made orbits coarser 535 if orbits_of_subgroup.mcr[OP_find(orbits_of_subgroup, minimal_in_primary_orbit)] != minimal_in_primary_orbit: 536 continue # main loop 537 if bitset_check(vertices_have_been_reduced, current_ps.depth): 538 bitset_and(vertices_to_split[current_ps.depth], vertices_to_split[current_ps.depth], minimal_cell_reps_of_generators[index_in_fp_and_mcr]) 539 continue # main loop 540 if not possible: 541 possible = 1 542 i = current_ps.depth 543 current_ps.depth = min(first_kids_are_same-1, current_kids_are_same-1) 544 if i == current_kids_are_same: 545 continue # main loop 546 if index_in_fp_and_mcr < len_of_fp_and_mcr - 1: 547 index_in_fp_and_mcr += 1 548 bitset_zero(fixed_points_of_generators[index_in_fp_and_mcr]) 549 bitset_zero(minimal_cell_reps_of_generators[index_in_fp_and_mcr]) 550 j = current_ps.depth 551 current_ps.depth = i # just for mcr and fixed functions... 552 for i from 0 <= i < n: 553 if PS_is_mcr(current_ps, i): 554 bitset_set(minimal_cell_reps_of_generators[index_in_fp_and_mcr], i) 555 if PS_is_fixed(current_ps, i): 556 bitset_set(fixed_points_of_generators[index_in_fp_and_mcr], i) 557 current_ps.depth = j 558 if bitset_check(vertices_have_been_reduced, current_ps.depth): 559 bitset_and(vertices_to_split[current_ps.depth], vertices_to_split[current_ps.depth], minimal_cell_reps_of_generators[index_in_fp_and_mcr]) 560 561 # End of main loop. 562 563 if possible and not unknown: 564 for i from 0 <= i < n: 565 output[left_ps.entries[i]] = current_ps.entries[i] 566 else: 567 sage_free(output) 568 output = NULL 569 570 # Deallocate: 571 for i from 0 <= i < len_of_fp_and_mcr: 572 bitset_clear(fixed_points_of_generators[i]) 573 bitset_clear(minimal_cell_reps_of_generators[i]) 574 for i from 0 <= i < n: 575 bitset_clear(vertices_to_split[i]) 576 bitset_clear(vertices_have_been_reduced) 577 sage_free(indicators) 578 sage_free(fixed_points_of_generators) 579 sage_free(minimal_cell_reps_of_generators) 580 sage_free(vertices_to_split) 581 sage_free(permutation) 582 sage_free(id_perm) 583 sage_free(cells_to_refine_by) 584 sage_free(vertices_determining_current_stack) 585 PS_dealloc(current_ps) 586 PS_dealloc(left_ps) 587 OP_dealloc(orbits_of_subgroup) 588 if first_ps is not NULL: PS_dealloc(first_ps) 589 590 return output 591 592 593 594 595 -
sage/groups/perm_gps/partn_ref/refinement_binary.pxd
diff -r 0d158c58d1c2 -r 2df5cad14396 sage/groups/perm_gps/partn_ref/refinement_binary.pxd
a b 8 8 9 9 include '../../../ext/cdefs.pxi' 10 10 include '../../../ext/stdsage.pxi' 11 include ' ../../../misc/bitset_pxd.pxi'11 include 'data_structures_pxd.pxi' # includes bitsets 12 12 13 13 from sage.rings.integer cimport Integer 14 from sage.groups.perm_gps.partn_ref.automorphism_group_canonical_label cimport PartitionStack, PS_print, PS_new, PS_dealloc, PS_clear, PS_is_discrete, PS_move_min_to_front, PS_num_cells, get_aut_gp_and_can_lab, aut_gp_and_can_lab_return 14 from sage.groups.perm_gps.partn_ref.automorphism_group_canonical_label cimport get_aut_gp_and_can_lab, aut_gp_and_can_lab_return 15 from double_coset cimport double_coset 15 16 16 17 cdef class BinaryCodeStruct: 17 18 cdef bitset_s *alpha_is_wd # single bitset of length nwords + degree … … 36 37 cdef int ith_word_nonlinear(BinaryCodeStruct, int, bitset_s *) 37 38 38 39 cdef int refine_by_bip_degree(PartitionStack *, object, int *, int) 39 cdef int compare_linear_codes(int *, int *, object )40 cdef int compare_nonlinear_codes(int *, int *, object )40 cdef int compare_linear_codes(int *, int *, object, object) 41 cdef int compare_nonlinear_codes(int *, int *, object, object) 41 42 cdef bint all_children_are_equivalent(PartitionStack *, object) 42 43 cdef inline int word_degree(PartitionStack *, BinaryCodeStruct, int, int, PartitionStack *) 43 44 cdef inline int col_degree(PartitionStack *, BinaryCodeStruct, int, int, PartitionStack *) -
sage/groups/perm_gps/partn_ref/refinement_binary.pyx
diff -r 0d158c58d1c2 -r 2df5cad14396 sage/groups/perm_gps/partn_ref/refinement_binary.pyx
a b 22 22 # http://www.gnu.org/licenses/ 23 23 #***************************************************************************** 24 24 25 include '../../../misc/bitset.pxi' 25 include 'data_structures_pyx.pxi' # includes bitsets 26 26 27 from sage.matrix.matrix import is_Matrix 27 28 28 29 cdef class LinearBinaryCodeStruct(BinaryCodeStruct): … … 95 96 96 97 self.output = NULL 97 98 self.ith_word = &ith_word_linear 98 self.first_time = 199 99 100 100 def run(self, partition=None): 101 101 """ … … 238 238 part[i][j] = partition[i][j] 239 239 part[i][len(partition[i])] = -1 240 240 part[len(partition)] = NULL 241 self.first_time = 1 241 242 242 243 self.output = get_aut_gp_and_can_lab(self, part, self.degree, &all_children_are_equivalent, &refine_by_bip_degree, &compare_linear_codes, 1, 1, 1) 243 244 … … 295 296 if self.output is NULL: 296 297 self.run() 297 298 return [self.output.relabeling[i] for i from 0 <= i < self.degree] 299 300 def is_isomorphic(self, LinearBinaryCodeStruct other): 301 """ 302 Calculate whether self is isomorphic to other. 303 304 EXAMPLES: 305 sage: from sage.groups.perm_gps.partn_ref.refinement_binary import LinearBinaryCodeStruct 306 307 sage: B = LinearBinaryCodeStruct(Matrix(GF(2), [[1,1,1,1,0,0],[0,0,1,1,1,1]])) 308 sage: C = LinearBinaryCodeStruct(Matrix(GF(2), [[1,1,1,0,0,1],[1,1,0,1,1,0]])) 309 sage: B.is_isomorphic(C) 310 [0, 1, 2, 5, 3, 4] 311 312 """ 313 cdef int **part, i, j 314 cdef int *output, *ordering 315 partition = [range(self.degree)] 316 part = <int **> sage_malloc((len(partition)+1) * sizeof(int *)) 317 ordering = <int *> sage_malloc(self.degree * sizeof(int)) 318 if part is NULL or ordering is NULL: 319 if part is not NULL: sage_free(part) 320 if ordering is not NULL: sage_free(ordering) 321 raise MemoryError 322 for i from 0 <= i < len(partition): 323 part[i] = <int *> sage_malloc((len(partition[i])+1) * sizeof(int)) 324 if part[i] is NULL: 325 for j from 0 <= j < i: 326 sage_free(part[j]) 327 sage_free(part) 328 raise MemoryError 329 for j from 0 <= j < len(partition[i]): 330 part[i][j] = partition[i][j] 331 part[i][len(partition[i])] = -1 332 part[len(partition)] = NULL 333 for i from 0 <= i < self.degree: 334 ordering[i] = i 335 self.first_time = 1 336 other.first_time = 1 337 338 output = double_coset(self, other, part, ordering, self.degree, &all_children_are_equivalent, &refine_by_bip_degree, &compare_linear_codes) 339 340 for i from 0 <= i < len(partition): 341 sage_free(part[i]) 342 sage_free(part) 343 sage_free(ordering) 344 345 if output is NULL: 346 return False 347 else: 348 output_py = [output[i] for i from 0 <= i < self.degree] 349 sage_free(output) 350 return output_py 298 351 299 352 def __dealloc__(self): 300 353 cdef int j … … 402 455 403 456 self.output = NULL 404 457 self.ith_word = &ith_word_nonlinear 405 self.first_time = 1406 458 407 459 def __dealloc__(self): 408 460 cdef int j … … 477 529 part[i][j] = partition[i][j] 478 530 part[i][len(partition[i])] = -1 479 531 part[len(partition)] = NULL 532 self.first_time = 1 480 533 481 534 self.output = get_aut_gp_and_can_lab(self, part, self.degree, &all_children_are_equivalent, &refine_by_bip_degree, &compare_nonlinear_codes, 1, 1, 1) 482 535 … … 535 588 self.run() 536 589 return [self.output.relabeling[i] for i from 0 <= i < self.degree] 537 590 591 def is_isomorphic(self, NonlinearBinaryCodeStruct other): 592 """ 593 Calculate whether self is isomorphic to other. 594 595 EXAMPLES: 596 sage: from sage.groups.perm_gps.partn_ref.refinement_binary import NonlinearBinaryCodeStruct 597 598 sage: B = NonlinearBinaryCodeStruct(Matrix(GF(2), [[1,1,1,1,0,0],[0,0,1,1,1,1]])) 599 sage: C = NonlinearBinaryCodeStruct(Matrix(GF(2), [[1,1,0,0,1,1],[1,1,1,1,0,0]])) 600 sage: B.is_isomorphic(C) 601 [2, 3, 0, 1, 4, 5] 602 603 """ 604 cdef int **part, i, j 605 cdef int *output, *ordering 606 partition = [range(self.degree)] 607 part = <int **> sage_malloc((len(partition)+1) * sizeof(int *)) 608 ordering = <int *> sage_malloc(self.degree * sizeof(int)) 609 if part is NULL or ordering is NULL: 610 if part is not NULL: sage_free(part) 611 if ordering is not NULL: sage_free(ordering) 612 raise MemoryError 613 for i from 0 <= i < len(partition): 614 part[i] = <int *> sage_malloc((len(partition[i])+1) * sizeof(int)) 615 if part[i] is NULL: 616 for j from 0 <= j < i: 617 sage_free(part[j]) 618 sage_free(part) 619 raise MemoryError 620 for j from 0 <= j < len(partition[i]): 621 part[i][j] = partition[i][j] 622 part[i][len(partition[i])] = -1 623 part[len(partition)] = NULL 624 for i from 0 <= i < self.degree: 625 ordering[i] = i 626 self.first_time = 1 627 other.first_time = 1 628 629 output = double_coset(self, other, part, ordering, self.degree, &all_children_are_equivalent, &refine_by_bip_degree, &compare_nonlinear_codes) 630 631 for i from 0 <= i < len(partition): 632 sage_free(part[i]) 633 sage_free(part) 634 sage_free(ordering) 635 636 if output is NULL: 637 return False 638 else: 639 output_py = [output[i] for i from 0 <= i < self.degree] 640 sage_free(output) 641 return output_py 642 538 643 cdef int ith_word_nonlinear(BinaryCodeStruct self, int i, bitset_s *word): 539 644 cdef NonlinearBinaryCodeStruct NBCS = <NonlinearBinaryCodeStruct> self 540 645 bitset_copy(word, &NBCS.words[i]) … … 606 711 if necessary_to_split_cell: 607 712 invariant += 8 608 713 first_largest_subcell = sort_by_function(col_ps, current_cell, col_degrees, col_counts, col_output, BCS.nwords+1) 714 invariant += col_degree(col_ps, BCS, i-1, ctrb[current_cell_against], word_ps) 609 715 invariant += first_largest_subcell 610 716 against_index = current_cell_against 611 717 while against_index < ctrb_len: … … 622 728 r += 1 623 729 if r >= i: 624 730 break 625 invariant += col_degree(col_ps, BCS, i-1, ctrb[current_cell_against], word_ps)626 731 invariant += (i - current_cell) 627 732 current_cell = i 628 733 else: … … 641 746 if necessary_to_split_cell: 642 747 invariant += 64 643 748 first_largest_subcell = sort_by_function(word_ps, current_cell, word_degrees, word_counts, word_output, BCS.degree+1) 749 invariant += word_degree(word_ps, BCS, i-1, ctrb[current_cell_against], col_ps) 644 750 invariant += first_largest_subcell 645 751 against_index = current_cell_against 646 752 while against_index < ctrb_len: … … 658 764 r += 1 659 765 if r >= i: 660 766 break 661 invariant += word_degree(word_ps, BCS, i-1, ctrb[current_cell_against], col_ps)662 767 invariant += (i - current_cell) 663 768 current_cell = i 664 769 current_cell_against += 1 665 770 return invariant 666 771 667 cdef int compare_linear_codes(int *gamma_1, int *gamma_2, object S ):772 cdef int compare_linear_codes(int *gamma_1, int *gamma_2, object S1, object S2): 668 773 """ 669 Compare gamma_1( B) and gamma_2(B).774 Compare gamma_1(S1) and gamma_2(S2). 670 775 671 Return return -1 if gamma_1( B) < gamma_2(B), 0 if gamma_1(B) == gamma_2(B),672 1 if gamma_1( B) > gamma_2(B). (Just like the python \code{cmp}) function.776 Return return -1 if gamma_1(S1) < gamma_2(S2), 0 if gamma_1(S1) == gamma_2(S2), 777 1 if gamma_1(S1) > gamma_2(S2). (Just like the python \code{cmp}) function. 673 778 674 779 Abstractly, what this function does is relabel the basis of B by gamma_1 and 675 780 gamma_2, run a row reduction on each, and verify that the matrices are the … … 680 785 681 786 INPUT: 682 787 gamma_1, gamma_2 -- list permutations (inverse) 683 S -- a binary code struct object788 S1, S2 -- binary code struct objects 684 789 685 790 """ 686 791 cdef int i, piv_loc_1, piv_loc_2, cur_col, cur_row=0 687 792 cdef bint is_pivot_1, is_pivot_2 688 cdef LinearBinaryCodeStruct BCS = <LinearBinaryCodeStruct> S 689 cdef bitset_s *basis_1 = BCS.scratch_bitsets # len = dim 690 cdef bitset_s *basis_2 = &BCS.scratch_bitsets[BCS.dimension] # len = dim 691 cdef bitset_s *pivots = &BCS.scratch_bitsets[2*BCS.dimension] # len 1 692 cdef bitset_s *temp = &BCS.scratch_bitsets[2*BCS.dimension+1] # len 1 693 for i from 0 <= i < BCS.dimension: 694 bitset_copy(&basis_1[i], &BCS.basis[i]) 695 bitset_copy(&basis_2[i], &BCS.basis[i]) 793 cdef LinearBinaryCodeStruct BCS1 = <LinearBinaryCodeStruct> S1 794 cdef LinearBinaryCodeStruct BCS2 = <LinearBinaryCodeStruct> S2 795 cdef bitset_s *basis_1 = BCS1.scratch_bitsets # len = dim 796 cdef bitset_s *basis_2 = &BCS1.scratch_bitsets[BCS1.dimension] # len = dim 797 cdef bitset_s *pivots = &BCS1.scratch_bitsets[2*BCS1.dimension] # len 1 798 cdef bitset_s *temp = &BCS1.scratch_bitsets[2*BCS1.dimension+1] # len 1 799 for i from 0 <= i < BCS1.dimension: 800 bitset_copy(&basis_1[i], &BCS1.basis[i]) 801 bitset_copy(&basis_2[i], &BCS2.basis[i]) 696 802 bitset_zero(pivots) 697 for cur_col from 0 <= cur_col < BCS .degree:803 for cur_col from 0 <= cur_col < BCS1.degree: 698 804 is_pivot_1 = 0 699 805 is_pivot_2 = 0 700 for i from cur_row <= i < BCS .dimension:806 for i from cur_row <= i < BCS1.dimension: 701 807 if bitset_check(&basis_1[i], gamma_1[cur_col]): 702 808 is_pivot_1 = 1 703 809 piv_loc_1 = i 704 810 break 705 for i from cur_row <= i < BCS .dimension:811 for i from cur_row <= i < BCS1.dimension: 706 812 if bitset_check(&basis_2[i], gamma_2[cur_col]): 707 813 is_pivot_2 = 1 708 814 piv_loc_2 = i … … 724 830 bitset_xor(&basis_1[i], &basis_1[i], &basis_1[cur_row]) 725 831 if bitset_check(&basis_2[i], gamma_2[cur_col]): 726 832 bitset_xor(&basis_2[i], &basis_2[i], &basis_2[cur_row]) 727 for i from cur_row < i < BCS .dimension:833 for i from cur_row < i < BCS1.dimension: 728 834 if bitset_check(&basis_1[i], gamma_1[cur_col]): 729 835 bitset_xor(&basis_1[i], &basis_1[i], &basis_1[cur_row]) 730 836 if bitset_check(&basis_2[i], gamma_2[cur_col]): … … 736 842 return <int>bitset_check(&basis_2[i], gamma_2[cur_col]) - <int>bitset_check(&basis_1[i], gamma_1[cur_col]) 737 843 return 0 738 844 739 cdef int compare_nonlinear_codes(int *gamma_1, int *gamma_2, object S ):845 cdef int compare_nonlinear_codes(int *gamma_1, int *gamma_2, object S1, object S2): 740 846 """ 741 Compare gamma_1( B) and gamma_2(B).847 Compare gamma_1(S1) and gamma_2(S2). 742 848 743 Return return -1 if gamma_1( B) < gamma_2(B), 0 if gamma_1(B) == gamma_2(B),744 1 if gamma_1( B) > gamma_2(B). (Just like the python \code{cmp}) function.849 Return return -1 if gamma_1(S1) < gamma_2(S2), 0 if gamma_1(S1) == gamma_2(S2), 850 1 if gamma_1(S1) > gamma_2(S2). (Just like the python \code{cmp}) function. 745 851 746 852 INPUT: 747 853 gamma_1, gamma_2 -- list permutations (inverse) 748 S -- a binary code struct object854 S1, S2 -- a binary code struct object 749 855 750 856 """ 751 857 cdef int side=0, i, start, end, n_one_1, n_one_2, cur_col 752 858 cdef int where_0, where_1 753 cdef NonlinearBinaryCodeStruct BCS = <NonlinearBinaryCodeStruct> S 754 cdef bitset_s *B_1_0 = BCS.scratch_bitsets # nwords of len degree 755 cdef bitset_s *B_1_1 = &BCS.scratch_bitsets[BCS.nwords] # nwords of len degree 756 cdef bitset_s *B_2_0 = &BCS.scratch_bitsets[2*BCS.nwords] # nwords of len degree 757 cdef bitset_s *B_2_1 = &BCS.scratch_bitsets[3*BCS.nwords] # nwords of len degree 758 cdef bitset_s *dividers = &BCS.scratch_bitsets[4*BCS.nwords] # 1 of len nwords 859 cdef NonlinearBinaryCodeStruct BCS1 = <NonlinearBinaryCodeStruct> S1 860 cdef NonlinearBinaryCodeStruct BCS2 = <NonlinearBinaryCodeStruct> S2 861 cdef bitset_s *B_1_0 = BCS1.scratch_bitsets # nwords of len degree 862 cdef bitset_s *B_1_1 = &BCS1.scratch_bitsets[BCS1.nwords] # nwords of len degree 863 cdef bitset_s *B_2_0 = &BCS1.scratch_bitsets[2*BCS1.nwords] # nwords of len degree 864 cdef bitset_s *B_2_1 = &BCS1.scratch_bitsets[3*BCS1.nwords] # nwords of len degree 865 cdef bitset_s *dividers = &BCS1.scratch_bitsets[4*BCS1.nwords] # 1 of len nwords 759 866 cdef bitset_s *B_1_this, *B_1_other, *B_2_this, *B_2_other 760 for i from 0 <= i < BCS .nwords:761 bitset_copy(&B_1_0[i], &BCS .words[i])762 bitset_copy(&B_2_0[i], &BCS .words[i])867 for i from 0 <= i < BCS1.nwords: 868 bitset_copy(&B_1_0[i], &BCS1.words[i]) 869 bitset_copy(&B_2_0[i], &BCS2.words[i]) 763 870 bitset_zero(dividers) 764 bitset_set(dividers, BCS .nwords-1)871 bitset_set(dividers, BCS1.nwords-1) 765 872 766 for cur_col from 0 <= cur_col < BCS .degree:873 for cur_col from 0 <= cur_col < BCS1.degree: 767 874 if side == 0: 768 875 B_1_this = B_1_0 769 876 B_1_other = B_1_1 … … 776 883 B_2_other = B_2_0 777 884 side ^= 1 778 885 start = 0 779 while start < BCS .nwords:886 while start < BCS1.nwords: 780 887 end = start 781 888 while not bitset_check(dividers, end): 782 889 end += 1 … … 960 1067 def random_tests(t=10.0, n_max=50, k_max=6, nwords_max=200, perms_per_code=10, density_range=(.1,.9)): 961 1068 """ 962 1069 Tests to make sure that C(gamma(B)) == C(B) for random permutations gamma 963 and random codes B .1070 and random codes B, and that is_isomorphic returns an isomorphism. 964 1071 965 1072 INPUT: 966 1073 t -- run tests for approximately this many seconds … … 977 1084 978 1085 For each code B (B2) generated, we uniformly generate perms_per_code random 979 1086 permutations and verify that the canonical labels of B and the image of B 980 under the generated permutation are equal. 1087 under the generated permutation are equal, and check that the double coset 1088 function returns an isomorphism. 981 1089 982 1090 DOCTEST: 983 1091 sage: import sage.groups.perm_gps.partn_ref.refinement_binary … … 992 1100 from sage.combinat.permutation import Permutations 993 1101 from sage.matrix.constructor import random_matrix, matrix 994 1102 from sage.rings.finite_field import FiniteField as GF 995 cdef int h, i, j, n, k, num_tests = 0, num_codes = 0 , passed = 11103 cdef int h, i, j, n, k, num_tests = 0, num_codes = 0 996 1104 cdef LinearBinaryCodeStruct B, C 997 1105 cdef NonlinearBinaryCodeStruct B_n, C_n 998 1106 t_0 = walltime() … … 1040 1148 B_n_M[j,B_n_relab[h]] = bitset_check(&B_n.words[j], h) 1041 1149 C_n_M[j,C_n_relab[h]] = bitset_check(&C_n.words[j], h) 1042 1150 if B_M.row_space() != C_M.row_space(): 1043 print " B:"1151 print "can_lab error -- B:" 1044 1152 for j from 0 <= j < B.dimension: 1045 1153 print bitset_string(&B.basis[j]) 1046 1154 print perm 1047 1155 return 1048 1156 if sorted(B_n_M.rows()) != sorted(C_n_M.rows()): 1049 print " B_n:"1157 print "can_lab error -- B_n:" 1050 1158 for j from 0 <= j < B_n.nwords: 1051 1159 print bitset_string(&B_n.words[j]) 1052 1160 print perm 1053 1161 return 1162 isom = B.is_isomorphic(C) 1163 if not isom: 1164 print "isom -- B:" 1165 for j from 0 <= j < B.dimension: 1166 print bitset_string(&B.basis[j]) 1167 print perm 1168 print isom 1169 return 1170 isom = B_n.is_isomorphic(C_n) 1171 if not isom: 1172 print "isom -- B_n:" 1173 for j from 0 <= j < B_n.nwords: 1174 print bitset_string(&B_n.words[j]) 1175 print perm 1176 print isom 1177 return 1054 1178 1055 num_tests += perms_per_code1179 num_tests += 4*perms_per_code 1056 1180 num_codes += 2 1057 if passed:1058 print "All passed: %d random tests on %d codes."%(num_tests, num_codes)1181 1182 print "All passed: %d random tests on %d codes."%(num_tests, num_codes) 1059 1183 1060 1184 -
sage/groups/perm_gps/partn_ref/refinement_graphs.pxd
diff -r 0d158c58d1c2 -r 2df5cad14396 sage/groups/perm_gps/partn_ref/refinement_graphs.pxd
a b 8 8 9 9 include '../../../ext/cdefs.pxi' 10 10 include '../../../ext/stdsage.pxi' 11 include 'data_structures_pxd.pxi' # includes bitsets 11 12 12 13 from sage.graphs.base.c_graph cimport CGraph 13 14 from sage.graphs.base.sparse_graph cimport SparseGraph 14 15 from sage.graphs.base.dense_graph cimport DenseGraph 15 16 from sage.rings.integer cimport Integer 16 from sage.groups.perm_gps.partn_ref.automorphism_group_canonical_label cimport PartitionStack, PS_is_discrete, PS_move_min_to_front, PS_num_cells, get_aut_gp_and_can_lab, aut_gp_and_can_lab_return 17 from automorphism_group_canonical_label cimport get_aut_gp_and_can_lab, aut_gp_and_can_lab_return 18 from double_coset cimport double_coset 17 19 18 20 cdef class GraphStruct: 19 21 cdef CGraph G … … 22 24 cdef int *scratch # length 3n+1 23 25 24 26 cdef int refine_by_degree(PartitionStack *, object, int *, int) 25 cdef int compare_graphs(int *, int *, object )27 cdef int compare_graphs(int *, int *, object, object) 26 28 cdef bint all_children_are_equivalent(PartitionStack *, object) 27 29 cdef inline int degree(PartitionStack *, CGraph, int, int, bint) 28 30 cdef inline int sort_by_function(PartitionStack *, int, int *) -
sage/groups/perm_gps/partn_ref/refinement_graphs.pyx
diff -r 0d158c58d1c2 -r 2df5cad14396 sage/groups/perm_gps/partn_ref/refinement_graphs.pyx
a b 17 17 # Distributed under the terms of the GNU General Public License (GPL) 18 18 # http://www.gnu.org/licenses/ 19 19 #***************************************************************************** 20 21 include 'data_structures_pyx.pxi' # includes bitsets 22 23 def isomorphic(G1, G2, partition, ordering2, dig, use_indicator_function, sparse=False): 24 """ 25 Tests whether two graphs are isomorphic. 26 27 sage: from sage.groups.perm_gps.partn_ref.refinement_graphs import isomorphic 28 29 sage: G = Graph(2) 30 sage: H = Graph(2) 31 sage: isomorphic(G, H, [[0,1]], [0,1], 0, 1) 32 [0, 1] 33 sage: isomorphic(G, H, [[0,1]], [0,1], 0, 1) 34 [0, 1] 35 sage: isomorphic(G, H, [[0],[1]], [0,1], 0, 1) 36 [0, 1] 37 sage: isomorphic(G, H, [[0],[1]], [1,0], 0, 1) 38 [1, 0] 39 40 sage: G = Graph(3) 41 sage: H = Graph(3) 42 sage: isomorphic(G, H, [[0,1,2]], [0,1,2], 0, 1) 43 [0, 1, 2] 44 sage: G.add_edge(0,1) 45 sage: isomorphic(G, H, [[0,1,2]], [0,1,2], 0, 1) 46 False 47 sage: H.add_edge(1,2) 48 sage: isomorphic(G, H, [[0,1,2]], [0,1,2], 0, 1) 49 [1, 2, 0] 50 51 """ 52 cdef int **part 53 cdef int *output, *ordering 54 cdef CGraph G 55 cdef GraphStruct GS1 = GraphStruct() 56 cdef GraphStruct GS2 = GraphStruct() 57 cdef GraphStruct GS 58 cdef int i, j, n = -1 59 60 from sage.graphs.graph import GenericGraph, Graph, DiGraph 61 for G_in in [G1, G2]: 62 if G_in is G1: 63 GS = GS1 64 else: 65 GS = GS2 66 if isinstance(G_in, GenericGraph): 67 if n == -1: 68 n = G_in.num_verts() 69 elif n != G_in.num_verts(): 70 return False 71 G_in = G_in.copy() 72 if G_in.vertices() != range(n): 73 to = G_in.relabel(return_map=True) 74 frm = {} 75 for v in to.iterkeys(): 76 frm[to[v]] = v 77 partition = [[to[v] for v in cell] for cell in partition] 78 else: 79 to = range(n) 80 frm = to 81 if sparse: 82 G = SparseGraph(n) 83 else: 84 G = DenseGraph(n) 85 if G_in.is_directed(): 86 for i from 0 <= i < n: 87 for _,j,_ in G_in.outgoing_edge_iterator(i): 88 G.add_arc(i,j) 89 else: 90 for i from 0 <= i < n: 91 for _,j,_ in G_in.edge_iterator(i): 92 if j <= i: 93 G.add_arc(i,j) 94 G.add_arc(j,i) 95 elif isinstance(G_in, CGraph): 96 G = <CGraph> G_in 97 if n == -1: 98 n = G.num_verts 99 elif n != G.num_verts: 100 return False 101 to = range(n) 102 frm = to 103 else: 104 raise TypeError("G must be a Sage graph.") 105 GS.G = G 106 GS.directed = 1 if dig else 0 107 GS.use_indicator = 1 if use_indicator_function else 0 108 109 if n == 0: 110 return {} 111 112 part = <int **> sage_malloc((len(partition)+1) * sizeof(int *)) 113 ordering = <int *> sage_malloc(n * sizeof(int)) 114 if part is NULL or ordering is NULL: 115 if part is not NULL: sage_free(part) 116 if ordering is not NULL: sage_free(ordering) 117 raise MemoryError 118 for i from 0 <= i < len(partition): 119 part[i] = <int *> sage_malloc((len(partition[i])+1) * sizeof(int)) 120 if part[i] is NULL: 121 for j from 0 <= j < i: 122 sage_free(part[j]) 123 sage_free(part) 124 raise MemoryError 125 for j from 0 <= j < len(partition[i]): 126 part[i][j] = partition[i][j] 127 part[i][len(partition[i])] = -1 128 part[len(partition)] = NULL 129 for i from 0 <= i < n: 130 ordering[i] = ordering2[i] 131 132 GS1.scratch = <int *> sage_malloc((3*n+1) * sizeof(int)) 133 GS2.scratch = <int *> sage_malloc((3*n+1) * sizeof(int)) 134 if GS1.scratch is NULL or GS2.scratch is NULL: 135 if GS1.scratch is not NULL: sage_free(GS1.scratch) 136 if GS2.scratch is not NULL: sage_free(GS2.scratch) 137 for j from 0 <= j < len(partition): 138 sage_free(part[j]) 139 sage_free(part) 140 raise MemoryError 141 142 output = double_coset(GS1, GS2, part, ordering, n, &all_children_are_equivalent, &refine_by_degree, &compare_graphs) 143 144 for i from 0 <= i < len(partition): 145 sage_free(part[i]) 146 sage_free(part) 147 sage_free(ordering) 148 sage_free(GS1.scratch) 149 sage_free(GS2.scratch) 150 151 if output is NULL: 152 return False 153 else: 154 output_py = [output[i] for i from 0 <= i < n] 155 sage_free(output) 156 # TODO: figure out frm, to stuff to relabel for consistency with input 157 return output_py 20 158 21 159 def search_tree(G_in, partition, lab=True, dig=False, dict_rep=False, certify=False, 22 160 verbosity=0, use_indicator_function=True, sparse=False, … … 200 338 sage: st(G, [range(G.num_verts())])[1] == st(H, [range(H.num_verts())])[1] 201 339 True 202 340 341 sage: from sage.graphs.graph import graph_isom_equivalent_non_multi_graph 342 sage: G = Graph(multiedges=True, implementation='networkx') 343 sage: G.add_edge(('a', 'b')) 344 sage: G.add_edge(('a', 'b')) 345 sage: G.add_edge(('a', 'b')) 346 sage: G, Pi = graph_isom_equivalent_non_multi_graph(G, [['a','b']]) 347 sage: s,b = st(G, Pi, lab=False, dict_rep=True) 348 sage: sorted(b.items()) 349 [(('o', 'a'), 5), (('o', 'b'), 1), (('x', 0), 2), (('x', 1), 3), (('x', 2), 4)] 350 351 sage: st(Graph(':Dkw'), [range(5)], lab=False, dig=True) 352 [[4, 1, 2, 3, 0], [0, 2, 1, 3, 4]] 353 203 354 """ 204 355 cdef CGraph G 205 356 cdef int i, j, n … … 277 428 if dict_rep: 278 429 ddd = {} 279 430 for v in frm.iterkeys(): 280 if frm[v] != 0: 281 ddd[v] = frm[v] 282 else: 283 ddd[v] = n 431 ddd[frm[v]] = v if v != 0 else n 284 432 return_tuple.append(ddd) 285 433 if lab: 286 434 if isinstance(G_in, GenericGraph): … … 348 496 cdef int current_cell, i, r 349 497 cdef int first_largest_subcell 350 498 cdef int invariant = 1 499 cdef int max_degree 351 500 cdef int *degrees = GS.scratch # length 3n+1 352 501 cdef bint necessary_to_split_cell 353 502 cdef int against_index … … 358 507 invariant += 50 359 508 i = current_cell 360 509 necessary_to_split_cell = 0 510 max_degree = 0 361 511 while 1: 362 512 degrees[i-current_cell] = degree(PS, G, i, cells_to_refine_by[current_cell_against], 0) 363 513 if degrees[i-current_cell] != degrees[0]: 364 514 necessary_to_split_cell = 1 515 if degrees[i-current_cell] > max_degree: 516 max_degree = degrees[i-current_cell] 365 517 i += 1 366 518 if PS.levels[i-1] <= PS.depth: 367 519 break … … 369 521 if necessary_to_split_cell: 370 522 invariant += 10 371 523 first_largest_subcell = sort_by_function(PS, current_cell, degrees) 372 invariant += first_largest_subcell 524 invariant += first_largest_subcell + max_degree 373 525 against_index = current_cell_against 374 526 while against_index < ctrb_len: 375 527 if cells_to_refine_by[against_index] == current_cell: … … 385 537 r += 1 386 538 if r >= i: 387 539 break 388 invariant += degree(PS, G, i-1, cells_to_refine_by[current_cell_against], 0)389 540 invariant += (i - current_cell) 390 541 current_cell = i 391 542 if GS.directed: … … 396 547 invariant += 20 397 548 i = current_cell 398 549 necessary_to_split_cell = 0 550 max_degree = 0 399 551 while 1: 400 552 degrees[i-current_cell] = degree(PS, G, i, cells_to_refine_by[current_cell_against], 1) 401 553 if degrees[i-current_cell] != degrees[0]: 402 554 necessary_to_split_cell = 1 555 if degrees[i-current_cell] > max_degree: 556 max_degree = degrees[i-current_cell] 403 557 i += 1 404 558 if PS.levels[i-1] <= PS.depth: 405 559 break … … 407 561 if necessary_to_split_cell: 408 562 invariant += 7 409 563 first_largest_subcell = sort_by_function(PS, current_cell, degrees) 410 invariant += first_largest_subcell 564 invariant += first_largest_subcell + max_degree 411 565 against_index = current_cell_against 412 566 while against_index < ctrb_len: 413 567 if cells_to_refine_by[against_index] == current_cell: … … 425 579 r += 1 426 580 if r >= i: 427 581 break 428 invariant += degree(PS, G, i-1, cells_to_refine_by[current_cell_against], 1)429 582 invariant += (i - current_cell) 430 583 current_cell = i 431 584 current_cell_against += 1 … … 434 587 else: 435 588 return 0 436 589 437 cdef int compare_graphs(int *gamma_1, int *gamma_2, object S ):590 cdef int compare_graphs(int *gamma_1, int *gamma_2, object S1, object S2): 438 591 r""" 439 Compare gamma_1( G) and gamma_2(G).592 Compare gamma_1(S1) and gamma_2(S2). 440 593 441 Return return -1 if gamma_1( G) < gamma_2(G), 0 if gamma_1(G) ==442 gamma_2( G), 1 if gamma_1(G) > gamma_2(G). (Just like the python594 Return return -1 if gamma_1(S1) < gamma_2(S2), 0 if gamma_1(S1) == 595 gamma_2(S2), 1 if gamma_1(S1) > gamma_2(S2). (Just like the python 443 596 \code{cmp}) function. 444 597 445 598 INPUT: 446 599 gamma_1, gamma_2 -- list permutations (inverse) 447 S -- a graph struct object600 S1, S2 -- graph struct objects 448 601 449 602 """ 450 603 cdef int i, j 451 cdef GraphStruct GS = <GraphStruct> S 452 cdef CGraph G = GS.G 453 for i from 0 <= i < G.num_verts: 454 for j from 0 <= j < G.num_verts: 455 if G.has_arc_unsafe(gamma_1[i], gamma_1[j]): 456 if not G.has_arc_unsafe(gamma_2[i], gamma_2[j]): 604 cdef GraphStruct GS1 = <GraphStruct> S1 605 cdef GraphStruct GS2 = <GraphStruct> S2 606 cdef CGraph G1 = GS1.G 607 cdef CGraph G2 = GS2.G 608 for i from 0 <= i < G1.num_verts: 609 for j from 0 <= j < G1.num_verts: 610 if G1.has_arc_unsafe(gamma_1[i], gamma_1[j]): 611 if not G2.has_arc_unsafe(gamma_2[i], gamma_2[j]): 457 612 return 1 458 elif G .has_arc_unsafe(gamma_2[i], gamma_2[j]):613 elif G2.has_arc_unsafe(gamma_2[i], gamma_2[j]): 459 614 return -1 460 615 return 0 461 616 … … 472 627 S -- a graph struct object 473 628 """ 474 629 cdef GraphStruct GS = <GraphStruct> S 630 if GS.directed: 631 return 0 475 632 cdef CGraph G = GS.G 476 633 cdef int i, n = PS.degree 477 634 cdef bint in_cell = 0 … … 622 779 def random_tests(t=10.0, n_max=60, perms_per_graph=10): 623 780 """ 624 781 Tests to make sure that C(gamma(G)) == C(G) for random permutations gamma 625 and random graphs G .782 and random graphs G, and that isomorphic returns an isomorphism. 626 783 627 784 INPUT: 628 785 t -- run tests for approximately this many seconds … … 637 794 638 795 For each graph G generated, we uniformly generate perms_per_graph random 639 796 permutations and verify that the canonical labels of G and the image of G 640 under the generated permutation are equal. 797 under the generated permutation are equal, and that the isomorphic function 798 returns an isomorphism. 641 799 642 800 TESTS: 643 801 sage: import sage.groups.perm_gps.partn_ref.refinement_graphs … … 651 809 from sage.misc.prandom import random, randint 652 810 from sage.graphs.graph_generators import GraphGenerators, DiGraphGenerators 653 811 from sage.combinat.permutation import Permutations 654 cdef int i, j, num_tests = 0, num_graphs = 0 , passed = 1812 cdef int i, j, num_tests = 0, num_graphs = 0 655 813 GG = GraphGenerators() 656 814 DGG = DiGraphGenerators() 657 815 t_0 = walltime() … … 663 821 G = GG.RandomGNP(n, p) 664 822 H = G.copy() 665 823 for i from 0 <= i < perms_per_graph: 824 G = H.copy() 666 825 G1 = search_tree(G, [G.vertices()])[1] 667 826 perm = list(S.random_element()) 668 827 perm = [perm[j]-1 for j from 0 <= j < n] 669 828 G.relabel(perm) 670 829 G2 = search_tree(G, [G.vertices()])[1] 671 830 if G1 != G2: 672 print " FAILURE: graph6-"831 print "search_tree FAILURE: graph6-" 673 832 print H.graph6_string() 674 833 print perm 675 passed = 0 834 return 835 isom = isomorphic(G, H, [range(n)], range(n), 0, 1) 836 if not isom or G.relabel(isom, inplace=False) != H: 837 print "isom FAILURE: graph6-" 838 print H.graph6_string() 839 print perm 840 return 676 841 677 842 D = DGG.RandomDirectedGNP(n, p) 678 843 D.loops(True) … … 681 846 D.add_edge(i,i) 682 847 E = D.copy() 683 848 for i from 0 <= i < perms_per_graph: 849 D = E.copy() 684 850 D1 = search_tree(D, [D.vertices()], dig=True)[1] 685 851 perm = list(S.random_element()) 686 852 perm = [perm[j]-1 for j from 0 <= j < n] 687 853 D.relabel(perm) 688 854 D2 = search_tree(D, [D.vertices()], dig=True)[1] 689 855 if D1 != D2: 690 print " FAILURE: dig6-"856 print "search_tree FAILURE: dig6-" 691 857 print E.dig6_string() 692 858 print perm 693 passed = 0 694 num_tests += 2*perms_per_graph 859 return 860 isom = isomorphic(D, E, [range(n)], range(n), 1, 1) 861 if not isom or D.relabel(isom, inplace=False) != E: 862 print "isom FAILURE: dig6-" 863 print E.dig6_string() 864 print perm 865 print isom 866 return 867 num_tests += 4*perms_per_graph 695 868 num_graphs += 2 696 if passed: 697 print "All passed: %d random tests on %d graphs."%(num_tests, num_graphs) 869 print "All passed: %d random tests on %d graphs."%(num_tests, num_graphs) 698 870 699 871 -
sage/groups/perm_gps/partn_ref/refinement_matrices.pxd
diff -r 0d158c58d1c2 -r 2df5cad14396 sage/groups/perm_gps/partn_ref/refinement_matrices.pxd
a b 8 8 9 9 include '../../../ext/cdefs.pxi' 10 10 include '../../../ext/stdsage.pxi' 11 include ' ../../../misc/bitset_pxd.pxi'11 include 'data_structures_pxd.pxi' # includes bitsets 12 12 13 13 from sage.rings.integer cimport Integer 14 from sage.groups.perm_gps.partn_ref.automorphism_group_canonical_label cimport PartitionStack, PS_new, PS_dealloc, PS_copy_from_to, get_aut_gp_and_can_lab, aut_gp_and_can_lab_return 15 from sage.groups.perm_gps.partn_ref.refinement_binary cimport NonlinearBinaryCodeStruct, refine_by_bip_degree 16 from sage.groups.perm_gps.partn_ref.refinement_binary cimport all_children_are_equivalent as all_binary_children_are_equivalent 14 from automorphism_group_canonical_label cimport get_aut_gp_and_can_lab, aut_gp_and_can_lab_return 15 from refinement_binary cimport NonlinearBinaryCodeStruct, refine_by_bip_degree 16 from refinement_binary cimport all_children_are_equivalent as all_binary_children_are_equivalent 17 from double_coset cimport double_coset 17 18 18 19 cdef class MatrixStruct: 19 20 cdef list symbol_structs … … 26 27 cdef aut_gp_and_can_lab_return *output 27 28 28 29 cdef int refine_matrix(PartitionStack *, object, int *, int) 29 cdef int compare_matrices(int *, int *, object )30 cdef int compare_matrices(int *, int *, object, object) 3
