- Code: Select all
n1,n2 = 10,10
disallow_pyramids1 = True
disallow_magbicups1 = False
disallow_adjacents1 = False
disallow_pyramids2 = True
disallow_magbicups2 = False
disallow_adjacents2 = False
disallow_simultaneous1and2 = False
# Keep in mind the operator precedence:
# arithmetic operations (+ - * //) are evaluated first, then
# bit shifts (<< >>), then other bitwise operations (& | ^).
# no augment = 00, pyramid augment = 01,
# ortho augment = 10, gyro augment = 11 (binary)
m = max(n1, n2)
all_bits = (1 << 2*m) - 1 # 1111...1111
even_bits = all_bits // 3 # 0101...0101
odd_bits = even_bits << 1 # 1010...1010
limit1 = 1 << 2*n1
limit2 = 1 << 2*n2
def pyramids(x):
"""Keep the '01' bit-pairs in x, and set '10' and '11' to '00'.
>>> pyramids(0b00101101) == 0b00000001
True
"""
return x & even_bits & ~(x & odd_bits)>>1
def magbicups(x):
"""Keep the '10' and '11' bit-pairs in x, and set '01' to '00'.
>>> magbicups(0b00101101) == 0b00101100
True
"""
return (x & odd_bits) | (x & even_bits & (x & odd_bits)>>1)
def gyrate(x):
"""Keep the '01' bit-pairs in x, and swap '10' and '11'.
>>> gyrate(0b00101101) == 0b00111001
True
"""
return (x & odd_bits) | ((x & even_bits) ^ (x & odd_bits)>>1)
def rotate(x, num_places, total_places):
"""Shift bit-pairs in x right num_places; carry the remainder left.
It's assumed that x has total_places many bit-pairs, and that
num_places is between 0 and total_places (inclusive).
>>> rotate(0b00101101, 1, 4) == 0b01001011
True
"""
return x >> 2*num_places | (
(x & ((1<<2*num_places)-1)) << 2*(total_places - num_places))
def reverse(x, total_places):
"""Reverse the order of bit-pairs in x.
This doesn't completely reverse the order of bits; '01' gets moved,
but not flipped to '10'.
It's assumed that x has total_places many bit-pairs.
>>> reverse(0b00101101, 4) == 0b01111000
True
"""
y = 0
for i in range(total_places):
y |= (x>>2*i & 3) << 2*(total_places - 1 - i)
return y
def adjacents(x, total_places):
"""Keep each bit-pair in x with a non-zero bit-pair to its left.
This is cyclic; the leftmost bit-pair is kept if the rightmost
bit-pair is non-zero.
It's assumed that x has total_places many bit-pairs.
>>> adjacents(0b00101101, 4) == 0b00001101
True
"""
x_left = rotate(x, 1, total_places)
# The bit-pair in x_left at the kth place is the bit-pair in x to
# the left of the kth place. It moved from left to right.
x_left_nonzero = (x_left & even_bits) | (x_left & odd_bits)>>1
# Multiply by 3 to replace each '01' with '11'.
return x & x_left_nonzero*3
count = 0
for ring1 in range(limit1):
if (disallow_pyramids1 and pyramids(ring1)
or disallow_magbicups1 and magbicups(ring1)
or disallow_adjacents1 and adjacents(ring1, n1)):
continue
for ring2 in range(limit2):
if (disallow_pyramids2 and pyramids(ring2)
or disallow_magbicups2 and magbicups(ring2)
or disallow_adjacents2 and adjacents(ring2, n2)
or disallow_simultaneous1and2 and ring1 and ring2):
continue
rings1and2 = ring1 << 2*n2 | ring2
is_least = True
i = 0
while i < 2 and is_least:
ring1_i = reverse(ring1, n1) if i else ring1
ring2_i = gyrate(ring2) if i else ring2
j = 0
while j < 2 and is_least:
ring2_ij = reverse(ring2_i, n2) if j else ring2_i
ring1_ij = gyrate(ring1_i) if j else ring1_i
k = 0
while k < n1 and is_least:
ring1_ijk = rotate(ring1_ij, k, n1)
ring2_ijk = gyrate(ring2_ij) if k & 1 else ring2_ij
l = 0
while l < n2 and is_least:
ring2_ijkl = rotate(ring2_ijk, l, n2)
ring1_ijkl = gyrate(ring1_ijk) if l & 1 else ring1_ijk
new_rings1and2 = ring1_ijkl << 2*n2 | ring2_ijkl
new_rings2and1 = ring2_ijkl << 2*n1 | ring1_ijkl
is_least &= rings1and2 <= new_rings1and2
is_least &= n1 != n2 or rings1and2 <= new_rings2and1
l += 1
k += 1
j += 1
i += 1
count += is_least
print(count)
(And I have other chunks of code to more efficiently handle special cases, such as when both rings can't be augmented at the same time, or when only pyramid augments are possible.)
Using this (with the first few lines changed), I got mostly the same results as in quickfur's list. The only exceptions had both rings augmentable at the same time, and at least one ring gyratably augmentable:
4,8-duoprism: 152 augmentations
5,6-duoprism: 66 augmentations
5,8-duoprism: 162 augmentations
5,10-duoprism: 2702 augmentations
8,8-duoprism: 429 augmentations (possibly wrong, because of relation to tesseract)
10,10-duoprism: 4924629 augmentations (took about 9 hours with the code in this post, vs. 4 hours with the previous version)
Again, these counts include the un-augmented duoprisms.
If only one ring is augmentable at a time, then quickfur's operation of reversing both rings has the same effect as reversing one and gyrating the other. (Reversing no augments is the same as gyrating no augments.) So the false symmetry happens to be equivalent to the true symmetry, and the count is correct, in this case.
If both rings are augmentable at the same time, but only with pyramids (so both have size at most 5), then reversing both has the same effect as reversing and gyrating both. This is a true symmetry of the duoprism, but still the reflection is missing. It turns out that the augmentations of a ring with size 3, 4, or 5 all have reflection symmetry anyway; i.e. reversing it has the same effect as rotating it. So the reflection symmetry doesn't need to be included explicitly, and the count is correct, in this case.