Commit 2ea6081c authored by Adam P. Goucher's avatar Adam P. Goucher

We can now determine the symmetries of a ruletree

parent 35efc7e2
Pipeline #49984525 passed with stages
in 7 minutes and 15 seconds
......@@ -44,10 +44,6 @@ def adjugate(mat):
'''
return [list(adjugate_row(mat, j)) for j in range(len(mat))]
def matmulvec(m, v):
pass
def matperms(pts):
n = len(pts)
......
......@@ -3,6 +3,8 @@ from ast import literal_eval
from .writetree import RuleTree
from .automorph import matperms
# Named neighbourhoods:
nhoods = {'2': [(-1, 0), (1, 0), (0, 0), (0, 0)],
'4': [(0, -1), (-1, 0), (1, 0), (0, 1), (0, 0), (0, 0)],
......@@ -84,6 +86,18 @@ def normalise_neighbourhood(nhood):
return [(x - x0, y - y0) for (x, y) in nhood]
def get_symmetries(n_states, nhood, list_of_nodes):
numInputs = GetNumberOfInputs(nhood)
rt = compress_tree(list_of_nodes, n_states, numInputs, seqonly=False)
pts = nhood[:numInputs]
perms = matperms(pts)
perms = [p for p in perms if rt.invariant(p)]
return perms
def optimise_tree(n_states, nhood, list_of_nodes):
numInputs = GetNumberOfInputs(nhood)
......
......@@ -163,6 +163,21 @@ class RuleTree:
return self._treecompare(other, self.curndd, other.curndd)
def invariant(self, perm):
other = RuleTree(self.numStates, self.numInputs, initialise=False)
other.seq = list(self.seq)
other._shrink()
perm = list(perm)
for _ in range(len(perm)):
for i in range(len(perm) - 1):
if perm[i+1] < perm[i]:
perm[i], perm[i+1] = perm[i+1], perm[i]
other._shrink(swap_at=(len(perm) - i))
return (other == self)
def __ne__(self, other):
return not self.__eq__(other)
......
......@@ -5,6 +5,8 @@ import unittest
import lifelib.genera.rulefiles.parsetree as parsetree
import lifelib.genera.rulefiles.automorph as automorph
from lifelib.genera.rulefiles import table_to_tree
class TestTreeduce(unittest.TestCase):
def test_adjugate(self):
......@@ -36,6 +38,8 @@ class TestTreeduce(unittest.TestCase):
self.assertEqual(len(mp), 2)
def test_fcc(self):
d3 = [(x, y, z) for x in [-1, 0, 1] for y in [-1, 0, 1] for z in [-1, 0, 1] if x*x + y*y + z*z == 2]
mp = list(automorph.matperms(d3))
......@@ -55,35 +59,50 @@ class TestTreeduce(unittest.TestCase):
mp = list(automorph.matperms(d4))
self.assertEqual(len(mp), 1152)
def test_rotate4(self):
'''
Tests that we can learn the symmetries of Langton's Loops from its
rule tree alone.
'''
# Load a rule table:
filename = os.path.join(lifelib.lifelib_dir, 'rules', 'source', 'Langtons-Loops.table')
with open(filename, 'r') as f:
list_of_lines = list(f)
# Convert it to a ruletree and optimise:
list_of_lines = table_to_tree(list_of_lines)
ruletree = parsetree.ParseRuleTree(list_of_lines)
ruletree = parsetree.optimise_tree(*ruletree)
# Determine that the rule has rotate4 symmetries but not reflections:
syms = parsetree.get_symmetries(*ruletree)
syms2 = [[0, 1, 2, 3, 4], [3, 0, 1, 2, 4], [1, 2, 3, 0, 4], [2, 3, 0, 1, 4]]
self.assertEqual(set(map(tuple, syms)), set(map(tuple, syms2)))
def test_reduce(self):
'''
Tests that we can recognise an hexagonal rule embedded as a Moore CA.
'''
# Load a ruletree as a list of lines:
filename = os.path.join(lifelib.lifelib_dir, 'rules', 'source', 'Hex-B2omS2.tree')
with open(filename, 'r') as f:
list_of_lines = list(f)
# Parse the ruletree and verify that it has the Moore neighbourhood:
ruletree = parsetree.ParseRuleTree(list_of_lines)
self.assertEqual(ruletree[1], [(-1, -1), (1, -1), (-1, 1), (1, 1), (0, -1), (-1, 0), (1, 0), (0, 1), (0, 0), (0, 0)])
self.assertEqual(len(ruletree[2]), 31)
# Optimise the tree and verify that the neighbourhood has reduced:
ruletree2 = parsetree.optimise_tree(*ruletree)
self.assertEqual(ruletree2[1], [(-1, -1), (1, 1), (0, -1), (-1, 0), (1, 0), (0, 1), (0, 0), (0, 0)])
self.assertEqual(len(ruletree2[2]), 27)
rt = parsetree.make_tree(*ruletree2)
rt2 = parsetree.make_tree(*ruletree2)
self.assertEqual(rt, rt2)
rt2._shrink(swap_at=5)
self.assertNotEqual(rt, rt2)
rt2._shrink(swap_at=3)
self.assertEqual(rt, rt2)
# Determine that the resulting rule has exactly 12 symmetries:
syms = parsetree.get_symmetries(*ruletree2)
self.assertEqual(len(syms), 12)
if __name__ == '__main__':
unittest.main()
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment