- 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.