Commit a964f6ae authored by Adam P. Goucher's avatar Adam P. Goucher

Support deficient analogues of isotropic rules

parent 41284c7e
Pipeline #43173265 (#68) passed with stages
in 6 minutes and 36 seconds
......@@ -8,7 +8,7 @@ import time
from . import genera
from ._version import __version__
from .genera import sanirule
from .genera import sanirule, genus_to_module, obtain_genus
__all__ = ['lifelib_dir', 'compile_rules', 'load_rules', 'reset_tree',
'sanirule', 'run_tests', 'add_cygdir', 'install_cygwin']
......@@ -418,12 +418,8 @@ def generate_code(rules, clean_before=False):
logic_directory = 'avxlife/lifelogic'
# Determine rule families from genera:
try:
families = [genera.rule_property(r, 'family') for r in rules]
except ImportError:
print("ImportError; current directory == %s" % os.getcwd())
raise
# Ensure modules are importable:
modules = [genus_to_module(obtain_genus(rulestring)) for rulestring in rules]
os.chdir(lifelib_dir)
......@@ -435,6 +431,18 @@ def generate_code(rules, clean_before=False):
os.makedirs(logic_directory)
os.chdir(logic_directory)
# Create the source code for the rules:
for r in rules:
genera.create_rule(r)
# Determine rule families from genera:
try:
families = [genera.rule_property(r, 'family') for r in rules]
except ImportError:
print("ImportError; current directory == %s" % os.getcwd())
raise
# Obtain integers describing valid mantissae:
def mant2int(m):
if hasattr(m, '__iter__'):
......@@ -498,10 +506,5 @@ def generate_code(rules, clean_before=False):
f.write('}\n')
# Create the source code for the rules:
for r in rules:
genera.create_rule(r)
os.chdir(lifelib_dir)
from .eightbit import *
from .eightbit import create_rule as make_header
from .rulefiles import rule2files
from .isotropic import str2tab
'''
The following code was written by Hadi Tarhini (for Python 3) and
subsequently modified to be compatible with both versions of Python.
'''
import sys
from os import path
N_HOODS = 'cekainyqjrtwz'
NAPKINS = {
k: dict(zip(N_HOODS, v)) for k, v in {
'0': '',
'1': ['00000001', '10000000'],
'2': ['01000001', '10000010', '00100001', '10000001', '10001000', '00010001'],
'3': ['01000101', '10100010', '00101001', '10000011', '11000001', '01100001', '01001001', '10010001', '10100001', '10001001'],
'4': ['01010101', '10101010', '01001011', '11100001', '01100011', '11000101', '01100101', '10010011', '10101001', '10100011', '11001001', '10110001', '10011001'],
'5': ['10111010', '01011101', '11010110', '01111100', '00111110', '10011110', '10110110', '01101110', '01011110', '01110110'],
'6': ['10111110', '01111101', '11011110', '01111110', '01110111', '11101110'],
'7': ['11111110', '01111111'],
'8': ''
}.items()
}
def order_segment(sz, segment):
if not segment or segment[0] == '-':
return [t for t in N_HOODS[:sz] if t not in segment]
return [t for t in N_HOODS if t in segment]
def combine_rstring(segment):
cop, last = {}, 0
for i, v in enumerate(segment, 1):
if v.isdigit():
after = next((idx for idx, j in enumerate(segment[i:], i) if j.isdigit()), len(segment))
cop[v] = order_segment(len(NAPKINS[v]), segment[i:after])
return cop
def replace_bind(transition, pre, sub='', count=0):
cop = []
for i in map(int, transition):
if not i:
cop.append(0)
continue
cop.append('{}{}_{}'.format(pre, sub, count))
count += 1
return cop
def write_table(fp, rname, n_states, n_live, d_vars, transitions):
fp.write('@RULE {}\n@TABLE\n'.format(rname))
fp.write('n_states:{}\nneighborhood:Moore\nsymmetries:rotate4reflect\n'.format(n_states))
# Variables
live = range(1, n_states)
for sub, (state, count) in d_vars.items():
range_ = {i for i in live if i != state}
if not range_:
continue
fp.write('\nvar not_{}_0 = {}'.format(sub, list(range_)).replace('[','{').replace(']','}'))
for n in range(1, count):
fp.write('\nvar not_{0}_{1} = not_{0}_0'.format(sub, n))
fp.write('\nvar any_0 = {}'.format(list(range(n_states))).replace('[','{').replace(']','}'))
for n in range(9):
fp.write('\nvar any_{} = any_0'.format(n))
fp.write('\nvar live_0 = {}'.format(list(live)).replace('[','{').replace(']','}'))
for n in range(1, n_live):
fp.write('\nvar live_{} = live_0'.format(n))
fp.write('\n')
# Transitions
for tr in transitions:
fp.write('\n' + ','.join(map(str, tr)))
def create_rule(rulestring):
transitions = []
bs = rulestring.split('d')[0]
PERM = (rulestring[-1] == 'p')
str2tab(bs) # Raise a NonCanonicalError if initial segment is non-canonical
birth, survival = tuple(map(str.strip, bs[1:].split('s')))
birth, survival = combine_rstring(birth), combine_rstring(survival)
n_live, sum_len = 0, 2
for counter, (num, subs) in enumerate(birth.items()):
if num == '0':
transitions.append([0]*9 + [1])
elif num == '8':
transitions.append([0] + ['live_{}'.format(i) for i in range(8)] + [1])
n_live = 8
else:
transitions += [[0] + replace_bind(NAPKINS[num][sub], 'not_', num+sub) + [idx] for idx, sub in enumerate(subs, sum_len)]
sum_len = 1 + transitions[-1][-1]
d_vars = {k: (tr[-1], sum(1 for i in tr if isinstance(i, str))) for k, tr in zip((n+j for n, li in birth.items() for j in N_HOODS[:len(NAPKINS[n])] if not li or j in li), transitions)}
transitions.append('')
END = 'live_0' if PERM else 1 # Bind if rule is to be 'permanently deficient'
for num, subs in survival.items():
if num == '0':
transitions.append(['live_0'] + [0]*8 + [END])
elif num == '8':
transitions.append(['live_{}'.format(i) for i in range(9)] + [END])
n_live = 9
else:
transitions += [['live_0'] + replace_bind(NAPKINS[num][sub], 'live', count=1) + [END] for sub in subs]
if survival:
n_live = max(n_live, *(sum(1 for i in tr if isinstance(i, str)) for tr in transitions[1+transitions.index(''):]))
n_states = 1 + max(t[-1] for t in transitions if t and isinstance(t[-1], int))
transitions.append(['any_{}'.format(i) for i in range(9)] + [0])
# Write temporary .rule file:
with open((rulestring+'.rule'), 'w') as fp:
write_table(fp, rulestring, n_states, n_live, d_vars, transitions)
# Convert .rule file into C/C++ code:
rule2files(rulestring + '.rule')
# Link code into lifelib:
make_header(rulestring)
......@@ -18,6 +18,7 @@ genus_list.append({'name': 'isogeny-hex', 'regex': 'g[1-9][0-9]*b[1-6omp-]*s[0-6
genus_list.append({'name': 'bsfkl', 'regex': 'b1?2?3?4?5?6?7?8?s0?1?2?3?4?5?6?7?8?f0?1?2?3?4?5?6?7?8?k0?1?2?3?4?5?6?7?8?l0?1?2?3?4?5?6?7?8?'})
genus_list.append({'name': 'hrot', 'regex': 'r[2345]b[0-9a-f]*s[0-9a-f]*z?'})
genus_list.append({'name': 'ghrot', 'regex': 'g[1-9][0-9]*r[2345]b[0-9a-f]*s[0-9a-f]*z?'})
genus_list.append({'name': 'deficient', 'regex': 'b[1-8ceaiknjqrytwz-]*s[0-8ceaiknjqrytwz-]*dp?'})
# This one must always be last as a 'catch-all' for custom rules with
# no more than 256 states:
......
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