Commit 85318ed0 by Adam P. Goucher

### Functionality to simplify ruletrees

parent 300dd11c
Pipeline #49745015 passed with stages
in 7 minutes and 41 seconds
 from .parsetable import GetNumberOfInputs from ast import literal_eval from .writetree import RuleTree # 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)], '8': [(-1, -1), (1, -1), (-1, 1), (1, 1), (0, -1), (-1, 0), (1, 0), (0, 1), (0, 0), (0, 0)]} def ReadRuleTree(list_of_lines): def ParseRuleTree(list_of_lines): numInputs = 0 num_nodes = 0 ... ... @@ -52,19 +54,86 @@ def ReadRuleTree(list_of_lines): # Tree node numbers = [int(x) for x in line.split()] depth = numbers[0] children = numbers[1:] if depth > 1: # Convert node number to index into uint32_t array: children = [n_states * (num_nodes - 1 - x) for x in children] list_of_nodes.append(children) list_of_nodes.append(numbers) if (len(list_of_nodes) != num_nodes): raise RuntimeError('%d nodes found; %d expected' % (len(list_of_nodes), num_nodes)) # We want the root to be position zero: list_of_nodes = list_of_nodes[::-1] return n_states, nhood, list_of_nodes def compress_tree(list_of_nodes, n_states, numInputs): rt = RuleTree(n_states, numInputs, initialise=False) rt.seq = list(map(tuple, list_of_nodes)) rt._shrink() return list(map(list, rt.seq)) def optimise_tree(n_states, nhood, list_of_nodes): numInputs = GetNumberOfInputs(nhood) # Perform optimisation of this tree: list_of_nodes = compress_tree(list_of_nodes, n_states, numInputs) # Determine which inputs are essential: essentials = [False] * numInputs for node in list_of_nodes: if len(set(node[1:])) > 1: essentials[-node[0]] = True # Flatten unnecessary layers: for node in list_of_nodes: depth = node[0] if (depth > 1): next_depth = list_of_nodes[node[-1]][0] if not essentials[-next_depth]: for j in range(1, len(node)): node[j] = list_of_nodes[node[j]][-1] while not essentials[-list_of_nodes[-1][0]]: x = list_of_nodes[-1][-1] list_of_nodes = list_of_nodes[:x+1] # Rename inputs: emap = [0] * (numInputs + 1) for i in range(1, numInputs + 1): emap[i] = emap[i-1] + (1 if essentials[-i] else 0) for node in list_of_nodes: node[0] = max(1, emap[node[0]]) # Shrink neighbourhood: new_inputs = [t for (x, t) in zip(essentials, nhood[:numInputs]) if x] nhood = new_inputs + nhood[numInputs:] numInputs = len(new_inputs) # Reoptimise: list_of_nodes = compress_tree(list_of_nodes, n_states, numInputs) return n_states, nhood, list_of_nodes def ReadRuleTree(list_of_lines): # Parse the actual file into a rule tree: ruletree = ParseRuleTree(list_of_lines) # Optimise the resulting rule tree: n_states, nhood, list_of_nodes = optimise_tree(*ruletree) # Serialise tree to an array: num_nodes = len(list_of_nodes) def serialise_node(numbers): depth = numbers[0] children = numbers[1:] if depth > 1: # Convert node number to index into uint32_t array: children = [n_states * (num_nodes - 1 - x) for x in children] return children list_of_nodes = [serialise_node(data) for data in list_of_nodes[::-1]] return n_states, nhood, list_of_nodes
 ... ... @@ -6,7 +6,7 @@ class RuleTree: written by Tim Hutton, Tom Rokicki, and Andrew Trevorrow. ''' def __init__(self, numStates, numInputs): def __init__(self, numStates, numInputs, initialise=True): self.numInputs = numInputs; ... ... @@ -22,7 +22,8 @@ class RuleTree: self.cache = {} self.shrinksize = 100 self._init_tree() if initialise: self._init_tree() def _init_tree(self): self.curndd = -1 ... ...
 # Automatically generated by make-ruletree.py. num_states=2 num_neighbors=8 num_nodes=31 1 0 0 2 0 0 1 1 1 2 0 2 3 1 3 1 0 1 2 5 0 3 3 6 4 4 7 2 0 5 2 2 0 3 9 10 3 10 1 4 11 12 5 8 13 3 3 10 4 15 12 3 1 1 4 12 17 5 16 18 6 14 19 7 20 20 8 21 21 3 6 1 4 23 17 4 17 17 5 24 25 6 19 26 7 27 27 8 28 28 9 22 29
 import os import lifelib import unittest import lifelib.genera.rulefiles.parsetree as parsetree class TestTreeduce(unittest.TestCase): def test_reduce(self): ''' Tests that we can recognise an hexagonal rule embedded as a Moore CA. ''' filename = os.path.join(lifelib.lifelib_dir, 'rules', 'source', 'Hex-B2omS2.tree') with open(filename, 'r') as f: list_of_lines = list(f) 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) 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) 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