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

Merge branch 'forestry'

parents ed42a46a f5c7f4e1
Pipeline #55523768 passed with stages
in 8 minutes
#ifndef LIFELIB_VERSION /*
__version__=[x.replace('"', '') for x in '''
*/
#define LIFELIB_VERSION "ll2.2.7"
#define LIFELIB_VERSION "ll2.2.8"
// '''.split() if ('ll' in x)][0][2:]
#endif
......@@ -474,16 +474,19 @@ def generate_code(rules, clean_before=False):
f.write('namespace apg {\n\n')
# Function to convert rulestring to rule integer:
not_used = True
f.write(' std::string get_zoi(std::string rule) {\n')
for (fam, r) in zip(families, rules):
if (fam >= 6):
f.write(' if (rule == "%s") { return "%s"; }\n' % (r, genera.rule_property(r, 'zoi')))
not_used = False
if not_used:
f.write(' (void) rule;\n')
f.write(' return "99";\n')
f.write(' }\n\n')
for prop in ['zoi', 'syms']:
not_used = True
f.write(' std::string get_%s(std::string rule) {\n' % prop)
for (fam, r) in zip(families, rules):
if (fam >= 6):
f.write(' if (rule == "%s") { return "%s"; }\n' % (r, genera.rule_property(r, prop)))
not_used = False
if not_used:
f.write(' (void) rule;\n')
f.write(' return "99";\n')
f.write(' }\n\n')
# Function to convert rulestring to rule integer:
f.write(' int rule2int(std::string rule) {\n')
......
......@@ -8,6 +8,11 @@ namespace apg {
return "99";
}
std::string get_syms(std::string rule) {
(void) rule;
return "99";
}
int rule2int(std::string rule) {
if (rule == "b3s23") { return 0; }
return -1;
......
......@@ -758,6 +758,12 @@ namespace apg {
return rep;
}
std::string wechslernone(std::vector<bitworld> &bwv, int64_t *rect) {
return canonise_orientation(bwv, rect[2], rect[3], rect[0], rect[1], 1, 0, 0, 1);
}
std::string wechslerise(std::vector<bitworld> &bwv, int64_t *rect) {
std::string rep = "#";
......
......@@ -2,6 +2,16 @@
import os
from .rulefiles import rules_dir
def syms(rulestring):
filename = rulestring if (rulestring[0] == 'x') else ('x' + rulestring)
with open(os.path.join(rules_dir, filename + '.h')) as f:
for line in f:
if 'SYMS="' in line:
return line.split('"')[1]
return "NONE"
def zoi(rulestring):
filename = rulestring if (rulestring[0] == 'x') else ('x' + rulestring)
......
from .parsetable import ReadRuleTable
from .parsetree import ReadRuleTree, SurplusTreeError
from .parsetree import ReadRuleTree, SurplusTreeError, FlattenRuleTree, get_symmetries
from .writetree import TransitionsToTree
from .writecode import NodesToCode
from .writecode import NodesToCode, MakeStaticTable
import os
import sys
from collections import OrderedDict
from ast import literal_eval
lifelib_dir = os.path.dirname(os.path.abspath(__file__))
while (os.path.basename(lifelib_dir) != 'lifelib'):
......@@ -25,13 +26,27 @@ def minkowski_symmetrise(nhood):
return set([tuple(((x - y) for (x, y) in zip(t, s))) for t in nhood for s in nhood])
def tree_to_code(lines):
def analyse_tree(segments):
lines = segments['@TREE']
print('Reading rule tree...')
n_states, nhood, list_of_nodes = ReadRuleTree(lines)
syms = get_symmetries(n_states, nhood, list_of_nodes)
print('Symmetries: %s' % syms)
if len(syms) == 12:
symstring = "HEXAGONAL"
elif len(syms) == 8:
symstring = "SQUARE"
else:
symstring = "NONE"
is16bit = (n_states > 256)
print('Generating code...')
lines = NodesToCode(nhood, list_of_nodes, is16bit)
print('Flattening tree...')
flattened_tree = FlattenRuleTree(n_states, nhood, list_of_nodes)
segments['@FLATTREE'] = MakeStaticTable(flattened_tree)
print('...done!')
# Determine zone of influence for rule:
......@@ -42,8 +57,41 @@ def tree_to_code(lines):
preamble = ['/* %d-bit code generated from ruletree */\n' % (16 if is16bit else 8)]
preamble += ['/* ZOI="%s" */\n' % zoi]
preamble += ['/* BITS="%d" */\n' % (16 if is16bit else 8)]
preamble += ['/* NHOOD="%s" */\n' % nhood]
preamble += ['/* SYMS="%s" */\n' % symstring]
segments['@PREAMBLE'] = preamble
def create_code(segments):
lines = []
template = 0
nhood = None
bits = None
for l in segments['@PREAMBLE']:
if (nhood is None) and ('NHOOD=' in l):
nhood = literal_eval(l.split('"')[1])
if (bits is None) and ('BITS=' in l):
bits = literal_eval(l.split('"')[1])
if '@FLATTREE' in segments:
template += 1
lines += segments['@FLATTREE']
lines += NodesToCode(nhood, (bits > 8))
if '@AIGER' in segments:
template += 2
raise NotImplementedError("AIGER is currently unsupported")
template = ["row_based_approach.h", "aiger_approach.h", "row_and_aiger.h"][template - 1]
# We have implemented iterate_var_row instead of iterate_var_grid:
lines.append('#include "%s"\n' % template)
segments['@CODE'] = lines
return (lines, preamble)
def segmentate(rulefile):
'''
......@@ -134,8 +182,10 @@ def rule2segs(rulefile):
# Apply transformations
if '@TREE' in segments:
segments['@CODE'], segments['@PREAMBLE'] = tree_to_code(segments['@TREE'])
if ('@PREAMBLE' in segments) and (('@FLATTREE' in segments) or ('@AIGER' in segments)):
create_code(segments)
elif '@TREE' in segments:
analyse_tree(segments)
elif '@TABLE' in segments:
segments['@TREE'] = table_to_tree(segments['@TABLE'])
else:
......
......@@ -175,7 +175,10 @@ def ReadRuleTree(list_of_lines):
ruletree = ParseRuleTree(list_of_lines)
# Optimise the resulting rule tree:
n_states, nhood, list_of_nodes = optimise_tree(*ruletree)
return optimise_tree(*ruletree)
def FlattenRuleTree(n_states, nhood, list_of_nodes):
# Determine whether rule is 2-state isotropic:
if (n_states == 2) and (GetNumberOfInputs(nhood) + 1 == len(nhood)):
......@@ -202,6 +205,4 @@ def ReadRuleTree(list_of_lines):
return children
list_of_nodes = [serialise_node(data) for data in list_of_nodes[::-1]]
return n_states, nhood, list_of_nodes
return [serialise_node(data) for data in list_of_nodes[::-1]]
from .parsetable import GetNumberOfInputs
from .parsetree import normalise_neighbourhood
def NodesToCode(nhood, nodes, is16bit):
def MakeStaticTable(nodes):
# Write rule tree in .data segment of the program:
lines = ["const static uint32_t __ruletree[] __attribute__((aligned(64))) = {\n"]
for (i, l) in enumerate(nodes):
body = ' ' + (','.join([('%du' % x) for x in l]))
body += ('};\n\n' if (i == len(nodes) - 1) else ',\n')
lines.append(body)
lines.append('\n')
return lines
def NodesToCode(nhood, is16bit):
numInputs = GetNumberOfInputs(nhood)
numOutputs = len(nhood) - numInputs
......@@ -22,16 +36,8 @@ def NodesToCode(nhood, nodes, is16bit):
if is16bit:
out_offsets += [t + 256 for t in out_offsets]
# Write rule tree in .data segment of the program:
lines = ["const static uint32_t __ruletree[] __attribute__((aligned(64))) = {\n"]
for (i, l) in enumerate(nodes):
body = ' ' + (','.join([('%du' % x) for x in l]))
body += ('};\n\n' if (i == len(nodes) - 1) else ',\n')
lines.append(body)
lines.append('\n')
# Hopefully simple enough to vectorise:
lines.append('void iterate_var_row(uint8_t* __restrict__ inrow, uint8_t* __restrict__ outrow) {\n')
lines = ['void iterate_var_row(uint8_t* __restrict__ inrow, uint8_t* __restrict__ outrow) {\n']
lines.append(' uint32_t temprow[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};\n')
for offset in in_offsets:
if (is16bit):
......@@ -47,7 +53,4 @@ def NodesToCode(nhood, nodes, is16bit):
lines.append('}\n')
lines.append('\n')
# We have implemented iterate_var_row instead of iterate_var_grid:
lines.append('#include "row_based_approach.h"\n')
return lines
......@@ -527,22 +527,27 @@ namespace apg {
return dt;
}
bool isHexagonal() {
std::string rule_symmetries() {
std::string rule = rulestring;
if (rule.length() == 0) { return false; }
if (rule.length() == 0) { return "NONE"; }
// Remove history suffix:
if ((rule.length() >= 8) && (rule.substr(rule.length() - 6) == "istory")) {
rule = rule.substr(0, rule.length() - 7);
}
std::string syms = get_syms(rule);
// Match uppercase 'H' and lowercase 'h':
return (((int) rule[rule.length() - 1]) & 31) == 8;
if (syms == "99") {
syms = ((((int) rule[rule.length() - 1]) & 31) == 8) ? "HEXAGONAL" : "SQUARE";
}
return syms;
}
std::string phase_wechsler() {
std::string phase_wechsler(std::string syms) {
/*
* Returns the extended Wechsler format for the current phase:
*/
......@@ -560,12 +565,16 @@ namespace apg {
// Remove redundant '_0' suffices:
bwv.pop_back();
}
if (isHexagonal()) {
if (syms == "HEXAGONAL") {
std::string s = wechslerhex(bwv);
return ((s.length() > 1280) ? "#" : s);
} else {
} else if (syms == "SQUARE") {
std::string s = wechslerise(bwv, bbox);
return ((s.length() > 1280) ? "#" : s);
} else {
std::string s = wechslernone(bwv, bbox);
return ((s.length() > 1280) ? "#" : s);
}
} else {
return "0";
......@@ -583,10 +592,12 @@ namespace apg {
uint64_t p = ascertain_period();
basepattern<I> x = advance(0);
std::string syms = rule_symmetries();
for (uint64_t t = 0; t < p; t++) {
if (t != 0) { x = x.advance((rulestring[1] == '0') ? 2 : 1); }
// rep = comprep(rep, x.flatlayer(0).wechsler());
rep = comprep(rep, x.phase_wechsler());
rep = comprep(rep, x.phase_wechsler(syms));
}
std::ostringstream ss;
......
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