Commit d2f7aae7 authored by Adam P. Goucher's avatar Adam P. Goucher 💬

Merge branch 'streamlife' into 'master'

Implemented streamlife

See merge request !1
parents 04b158d0 ba11d840
#pragma once
#include <stdint.h>
#include <cstring>
#include "lifeperm.h"
#include "lifelogic/iterators_all.h"
namespace apg {
uint64_t z64_centre_to_u64(uint64_t * inleaf, int x, int y) {
/*
* Provided this is inlined and x, y are compile-time constants,
* this should just involve 6 shifts, 3 ORs, and 2 ANDs:
*/
int xs = 4 + x;
int ys = (4 + y) << 3;
uint64_t bitmask = (0x0101010101010101ull << xs) - 0x0101010101010101ull;
uint64_t left = (inleaf[0] >> ys) | (inleaf[2] << (64 - ys));
uint64_t right = (inleaf[1] >> ys) | (inleaf[3] << (64 - ys));
uint64_t result = ((right & bitmask) << (8 - xs)) | ((left & (~bitmask)) >> xs);
return result;
}
uint64_t determine_direction(int rule, uint64_t * inleaf) {
uint64_t centre;
iterate_var_leaf(rule, -4, inleaf, &centre);
uint64_t dmap = 0;
dmap |= ((centre == z64_centre_to_u64(inleaf, -1, -1)) ? 1 : 0); // SE
dmap |= ((centre == z64_centre_to_u64(inleaf, 0, -2)) ? 2 : 0); // S
dmap |= ((centre == z64_centre_to_u64(inleaf, 1, -1)) ? 4 : 0); // SW
dmap |= ((centre == z64_centre_to_u64(inleaf, 2, 0)) ? 8 : 0); // W
dmap |= ((centre == z64_centre_to_u64(inleaf, 1, 1)) ? 16 : 0); // NW
dmap |= ((centre == z64_centre_to_u64(inleaf, 0, 2)) ? 32 : 0); // N
dmap |= ((centre == z64_centre_to_u64(inleaf, -1, 1)) ? 64 : 0); // NE
dmap |= ((centre == z64_centre_to_u64(inleaf, -2, 0)) ? 128 : 0); // E
uint64_t lmask = 0;
if (centre) {
if (dmap & 170) {
lmask |= 3;
}
if (dmap & 85) {
lmask |= 7;
}
// if (dmap) { std::cerr << centre << " " << dmap << std::endl; }
}
// Use a uint64 as an ordered pair of uint32s:
return (dmap | (lmask << 32));
}
}
/*
* This file is #included into each outer-totalistic rule namespace.
*/
uint64_t r32_centre_to_u64(uint32_t* d, int x, int y) {
// Not written in inline assembly for a change (!)
uint64_t z = 0;
for (int i = 11; i >= 4; i--) {
z = z << 8;
z |= (d[i+y] >> (12+x)) & 255;
}
return z;
}
void displaycentre(uint32_t *d) {
for (uint64_t i = 0; i < 16; i++) {
for (uint64_t j = 8; j < 24; j++) {
std::cerr << (((d[i] >> j) & 1) ? '*' : '.');
}
std::cerr << std::endl;
}
std::cerr << std::endl;
}
void iter4_var_leaf(uint64_t * inleaf, uint64_t * centres) {
/*
* Find the 8-by-8 centre after iterating a 16-by-16 leaf for a
* further 4 iterations in the rule.
*/
int bis = apg::best_instruction_set();
uint32_t d[16];
uint32_t e[16];
if (bis >= 9) {
apg::z64_to_r32_centre_avx(inleaf, d);
// displaycentre(d);
iterate_avx_16_12(d, e, 0, 0, 0, false);
iterate_avx_12_8(d+2, e+2, 0, 0, 0, false);
// displaycentre(d);
} else {
apg::z64_to_r32_centre_ssse3(inleaf, d);
iterate_sse2_16_12(d, e, 0, 0, 0, false);
iterate_sse2_12_8(d+2, e+2, 0, 0, 0, false);
}
centres[0] = r32_centre_to_u64(d, 0, 0);
// std::cerr << inleaf[0] << " " << inleaf[1] << " " << inleaf[2] << " " << inleaf[3] << ": " << centres[0] << std::endl;
}
bool iterate_var_leaf(int n, uint64_t * inleaves, uint64_t * outleaf) {
if (n == -4) {
/*
* This brings a whole new meaning to 'function overloading'.
* I'm going to attempt to justify this by claiming that MINUS n
* corresponds to MINUScule leaf iteration. So, for instance:
*
* iterate_var_leaf( 4, ...) <-- run a 32-by-32 tile 4 gens;
* iterate_var_leaf(-4, ...) <-- run a 16-by-16 tile 4 gens;
*/
iter4_var_leaf(inleaves, outleaf);
return false;
}
bool nochange = false;
int bis = apg::best_instruction_set();
uint32_t d[32];
if (bis >= 10) {
apg::z64_to_r32_avx2(inleaves, d);
nochange = (iterate_var_avx2(n, d) == n);
apg::r32_centre_to_z64_avx2(d, outleaf);
} else if (bis >= 9) {
apg::z64_to_r32_avx(inleaves, d);
nochange = (iterate_var_avx(n, d) == n);
apg::r32_centre_to_z64_avx(d, outleaf);
} else if (bis >= 7) {
apg::z64_to_r32_sse2(inleaves, d);
nochange = (iterate_var_sse2(n, d) == n);
apg::r32_centre_to_z64_sse4(d, outleaf);
} else {
apg::z64_to_r32_sse2(inleaves, d);
nochange = (iterate_var_sse2(n, d) == n);
apg::r32_centre_to_z64_ssse3(d, outleaf);
}
return nochange;
}
bool iterate_var_leaf(int n, uint64_t * inleaves, uint64_t * hleaves, uint64_t * outleaf) {
bool nochange = false;
int bis = apg::best_instruction_set();
uint32_t d[32];
uint32_t h[32];
if (bis >= 10) {
apg::z64_to_r32_avx2(inleaves, d);
apg::z64_to_r32_avx2(hleaves, h);
nochange = (iterate_var_avx2(n, d, h) == n);
apg::r32_centre_to_z64_avx2(d, outleaf);
apg::r32_centre_to_z64_avx2(h, outleaf + 4);
} else if (bis >= 9) {
apg::z64_to_r32_avx(inleaves, d);
apg::z64_to_r32_avx(hleaves, h);
nochange = (iterate_var_avx(n, d, h) == n);
apg::r32_centre_to_z64_avx(d, outleaf);
apg::r32_centre_to_z64_avx(h, outleaf + 4);
} else if (bis >= 7) {
apg::z64_to_r32_sse2(inleaves, d);
apg::z64_to_r32_sse2(hleaves, h);
nochange = (iterate_var_sse2(n, d, h) == n);
apg::r32_centre_to_z64_sse4(d, outleaf);
apg::r32_centre_to_z64_sse4(h, outleaf + 4);
} else {
apg::z64_to_r32_sse2(inleaves, d);
apg::z64_to_r32_sse2(hleaves, h);
nochange = (iterate_var_sse2(n, d, h) == n);
apg::r32_centre_to_z64_ssse3(d, outleaf);
apg::r32_centre_to_z64_ssse3(h, outleaf + 4);
}
return nochange;
}
bool iterate_var_leaf(int n, uint64_t * inleaves, uint64_t * hleaves, uint64_t * jleaves, uint64_t * outleaf) {
bool nochange = false;
int bis = apg::best_instruction_set();
uint32_t d[32];
uint32_t h[32];
uint32_t j[32];
if (bis >= 10) {
apg::z64_to_r32_avx2(inleaves, d);
apg::z64_to_r32_avx2(jleaves, j);
apg::z64_to_r32_avx2(hleaves, h);
nochange = (iterate_var_avx2(n, d, h, j) == n);
apg::r32_centre_to_z64_avx2(d, outleaf);
apg::r32_centre_to_z64_avx2(j, outleaf + 8);
apg::r32_centre_to_z64_avx2(h, outleaf + 4);
} else if (bis >= 9) {
apg::z64_to_r32_avx(inleaves, d);
apg::z64_to_r32_avx(jleaves, j);
apg::z64_to_r32_avx(hleaves, h);
nochange = (iterate_var_avx(n, d, h, j) == n);
apg::r32_centre_to_z64_avx(d, outleaf);
apg::r32_centre_to_z64_avx(j, outleaf + 8);
apg::r32_centre_to_z64_avx(h, outleaf + 4);
} else if (bis >= 7) {
apg::z64_to_r32_sse2(inleaves, d);
apg::z64_to_r32_sse2(jleaves, j);
apg::z64_to_r32_sse2(hleaves, h);
nochange = (iterate_var_sse2(n, d, h, j) == n);
apg::r32_centre_to_z64_sse4(d, outleaf);
apg::r32_centre_to_z64_sse4(j, outleaf + 8);
apg::r32_centre_to_z64_sse4(h, outleaf + 4);
} else {
apg::z64_to_r32_sse2(inleaves, d);
apg::z64_to_r32_sse2(jleaves, j);
apg::z64_to_r32_sse2(hleaves, h);
nochange = (iterate_var_sse2(n, d, h, j) == n);
apg::r32_centre_to_z64_ssse3(d, outleaf);
apg::r32_centre_to_z64_ssse3(j, outleaf + 8);
apg::r32_centre_to_z64_ssse3(h, outleaf + 4);
}
return nochange;
}
......@@ -43,5 +43,23 @@ namespace apg {
0x00ffff00u,
1, 2, 3, 4, 5, 6, 7, 0};
const static uint32_t __sixteen12[] __attribute__((aligned(64))) = {0x003ffc00u,
0x003ffc00u,
0x003ffc00u,
0x003ffc00u,
0x003ffc00u,
0x003ffc00u,
0x003ffc00u,
0x003ffc00u,
1, 2, 3, 4, 5, 6, 7, 0};
const static uint32_t __sixteen8[] __attribute__((aligned(64))) = {0x000ff000u,
0x000ff000u,
0x000ff000u,
0x000ff000u,
0x000ff000u,
0x000ff000u,
0x000ff000u,
0x000ff000u,
1, 2, 3, 4, 5, 6, 7, 0};
}
This diff is collapsed.
......@@ -12,6 +12,9 @@ namespace apg {
0, 0, 0, 0, 4, 0, 0, 0, 2, 0, 0, 0, 6, 0, 0, 0,
1, 0, 0, 0, 5, 0, 0, 0, 3, 0, 0, 0, 7, 0, 0, 0};
const static uint8_t __linvperm[] __attribute__((aligned(64))) = {0,
8, 4, 12, 1, 9, 5, 13, 2, 10, 6, 14, 3, 11, 7, 15,
0, 8, 4, 12, 1, 9, 5, 13, 2, 10, 6, 14, 3, 11, 7, 15};
void transpose_bytes_avx(uint64_t* a, uint64_t* b) {
......@@ -290,6 +293,60 @@ namespace apg {
}
void z64_to_r32_centre_ssse3(uint64_t* c, uint32_t* b) {
/*
* #ab#
* #cd# <--- [a, b, c, d]
*/
asm (
// Load from memory:
"movups (%0), %%xmm0 \n\t"
"movups 16(%0), %%xmm2 \n\t"
// Permute bytes:
"pshufb (%2), %%xmm0 \n\t"
"pshufb (%2), %%xmm2 \n\t"
// Dirty hack to perform << 8 and >> 8 during movups:
"movups %%xmm0, 1(%1) \n\t"
"movups %%xmm0, 15(%1) \n\t"
"movups %%xmm2, 33(%1) \n\t"
"movups %%xmm2, 47(%1) \n\t"
: /* no output operands -- implicitly volatile */
: "r" (c), "r" (b), "r" (__linvperm)
: "xmm0", "xmm1", "xmm2", "xmm3", "memory" );
}
void z64_to_r32_centre_avx(uint64_t* c, uint32_t* b) {
/*
* #ab#
* #cd# <--- [a, b, c, d]
*/
asm (
// Load from memory:
"vmovups (%0), %%xmm0 \n\t"
"vmovups 16(%0), %%xmm2 \n\t"
// Permute bytes:
"vpshufb (%2), %%xmm0, %%xmm0 \n\t"
"vpshufb (%2), %%xmm2, %%xmm2 \n\t"
// Dirty hack to perform << 8 and >> 8 during movups:
"vmovups %%xmm0, 1(%1) \n\t"
"vmovups %%xmm0, 15(%1) \n\t"
"vmovups %%xmm2, 33(%1) \n\t"
"vmovups %%xmm2, 47(%1) \n\t"
: /* no output operands -- implicitly volatile */
: "r" (c), "r" (b), "r" (__linvperm)
: "xmm0", "xmm1", "xmm2", "xmm3", "memory" );
}
void r32_centre_to_z64_ssse3(uint32_t* b, uint64_t* c) {
/*
* Selects the 16-by-16 square in the centre of a 32-by-32
......
......@@ -67,58 +67,6 @@ class iwriter:
self.printinstr('movdqa %s, %s' % (i2, o1))
self.printinstr('%s %s, %s' % (op, i1, o1))
def ntinit(self):
'''
Prepare lookup tables, masks, et cetera:
'''
regbytes = 32 if ('avx2' in self.iset) else 16
regname = '%%ymm' if ('avx2' in self.iset) else '%%xmm'
accessor = 'vmovdqu' if ('avx' in self.iset) else 'movups'
for i in xrange(8):
memloc = '(%2)' if (i == 0) else (str(32*i) + '(%2)')
self.printinstr('%s %s, %s' % (accessor, memloc, regname + str(i + 2)))
self.logicgate('pxor', 14, 14, 14)
def ntiter(self):
'''
Evaluates 16 or 32 cell-updates in 16 machine instructions (excluding
additional movdqa instructions emitted for SSE machines).
Assumes the following initial states:
xmm0: bytes containing neighbour states (0..255);
xmm1: bytes containing centre states (0..1);
xmm2..xmm7: lookup tables for pshufb;
xmm8: uniform array containing 0x7f;
xmm9: uniform array containing 0x70;
xmm14: uniform array containing 0x00.
The output will be stored in xmm10. Register xmm0 is clobbered.
'''
self.logicgate('pshufb', 0, 2, 10)
self.logicgate('pshufb', 0, 3, 11)
self.logicgate('pand', 8, 0, 0)
self.logicgate('pshufb', 0, 4, 12)
self.logicgate('pshufb', 0, 5, 13)
self.logicgate('pxor', 12, 10, 10)
self.logicgate('pxor', 13, 11, 11)
self.logicgate('pand', 9, 0, 0)
regname = '%%ymm' if ('avx2' in self.iset) else '%%xmm'
if ('avx' in self.iset):
self.printinstr('vpsrld $3, %s0, %s0' % (regname, regname))
else:
self.printinstr('psrld $3, %s0' % regname)
self.logicgate('por', 1, 0, 0)
self.logicgate('pshufb', 0, 6, 12)
self.logicgate('pshufb', 0, 7, 13)
self.logicgate('pand', 12, 10, 10)
self.logicgate('pand', 13, 11, 11)
self.logicgate('por', 11, 10, 10)
self.logicgate('pcmpeqb', 14, 10, 10)
def load_and_hshift(self, i, oddgen, terminal):
regbytes = 32 if ('avx2' in self.iset) else 16
......@@ -560,27 +508,6 @@ def gwli_bsi(f, bsi, msi):
f.write(' apg::r32_centre_to_z64_%s(d, outleaf);\n' % msi)
f.write(' apg::r32_centre_to_z64_%s(h, outleaf2);\n' % msi)
def wli_bsi(f, hist, bsi, msi):
f.write(' apg::z64_to_r32_%s(inleaves, d);\n' % bsi)
if (hist >= 2):
f.write(' apg::z64_to_r32_%s(jleaves, j);\n' % bsi)
if (hist >= 1):
f.write(' apg::z64_to_r32_%s(hleaves, h);\n' % bsi)
if (hist >= 2):
f.write(' nochange = (iterate_var_%s(n, d, h, j) == n);\n' % bsi)
elif (hist >= 1):
f.write(' nochange = (iterate_var_%s(n, d, h) == n);\n' % bsi)
else:
f.write(' nochange = (iterate_var_%s(n, d) == n);\n' % bsi)
f.write(' apg::r32_centre_to_z64_%s(d, outleaf);\n' % msi)
if (hist >= 2):
f.write(' apg::r32_centre_to_z64_%s(j, outleaf + 8);\n' % msi)
if (hist >= 1):
f.write(' apg::r32_centre_to_z64_%s(h, outleaf + 4);\n' % msi)
def write_all_iterators(f, hist, rules):
params = 'int n, uint64_t * inleaves'
......@@ -656,37 +583,6 @@ def write_all_iterators(f, hist, rules):
f.write(' return -1;\n')
f.write(' }\n\n')
def write_leaf_iterator(f, hist):
name = 'iterate_var_leaf'
params = 'int n, uint64_t * inleaves'
if (hist):
params += ', uint64_t * hleaves'
if (hist >= 2):
params += ', uint64_t * jleaves'
params += ', uint64_t * outleaf'
f.write(' bool %s(%s) {\n' % (name, params))
f.write(' bool nochange = false;\n')
f.write(' int bis = apg::best_instruction_set();\n')
f.write(' uint32_t d[32];\n')
if (hist >= 1):
f.write(' uint32_t h[32];\n')
if (hist >= 2):
f.write(' uint32_t j[32];\n')
f.write(' if (bis >= 10) {\n')
wli_bsi(f, hist, 'avx2', 'avx2')
f.write(' } else if (bis >= 9) {\n')
wli_bsi(f, hist, 'avx', 'avx')
f.write(' } else if (bis >= 7) {\n')
wli_bsi(f, hist, 'sse2', 'sse4')
f.write(' } else {\n')
wli_bsi(f, hist, 'sse2', 'ssse3')
f.write(' }\n')
f.write(' return nochange;\n')
f.write(' }\n\n')
def gwrite_leaf_iterator(f, nstates):
name = 'iterate_var_leaf'
......@@ -753,12 +649,6 @@ def makeiso(rulestring):
os.makedirs('lifelogic')
logstring = rulestring[rulestring.index('b'):]
'''
for iset in [['sse2'], ['sse2', 'avx'], ['sse2', 'avx', 'avx2']]:
with open(('lifelogic/llma_%s.asm' % iset[-1]), 'w') as f:
ix = iwriter(f, iset)
ix.isogen()
'''
with open('lifelogic/iterators_%s.h' % rulestring, 'w') as f:
f.write('#pragma once\n')
......@@ -791,14 +681,6 @@ def makeasm(rulestring):
f.write('#include "../eors.h"\n')
f.write('namespace %s {\n\n' % rulestring.replace('-', '_'))
'''
for (x, y) in [(28, '0x3ffffffcu'), (24, '0x0ffffff0u'), (20, '0x03ffffc0u'), (16, '0x00ffff00u')]:
f.write(' const static uint32_t __sixteen%d[] __attribute__((aligned(64))) = {' % x)
for i in xrange(8):
f.write('%s,\n ' % y)
f.write('1, 2, 3, 4, 5, 6, 7, 0};\n\n')
'''
for iset in [['sse2'], ['sse2', 'avx'], ['sse2', 'avx', 'avx2']]:
iw = iwriter(f, iset)
if (rulestring[0] == 'g'):
......@@ -809,13 +691,14 @@ def makeasm(rulestring):
iw.write_function(rulestring, 28, 24)
iw.write_function(rulestring, 24, 20)
iw.write_function(rulestring, 20, 16)
iw.write_function(rulestring, 16, 12)
iw.write_function(rulestring, 12, 8)
iw.write_iterator()
if (rulestring[0] == 'g'):
gwrite_leaf_iterator(f, int(rulestring[1:rulestring.index('b')]))
else:
for hist in xrange(3):
write_leaf_iterator(f, hist)
f.write('\n#include "../leaf_iterators.h"\n')
f.write('}\n')
def main():
......@@ -833,7 +716,7 @@ def main():
print("python rule2asm.py b3s23 b38s23 g4b2s345")
exit(1)
if (len(rules) > 8):
print("apglib supports a maximum of 8 different rules")
print("lifelib supports a maximum of 8 different rules")
exit(1)
for rulestring in rules:
......
#pragma once
#include <stdint.h>
#include <cstring>
#include <iostream>
#include "lifeperm.h"
#include "lifelogic/iterators_all.h"
......
#pragma once
#define LIFELIB_VERSION "ll1.23"
#define LIFELIB_VERSION "ll1.3"
#include "bitbounds.h"
#include <stdint.h>
......
......@@ -34,17 +34,32 @@ namespace apg {
template<typename I>
struct hypernode {
I index;
I index2;
uint32_t depth;
hypernode(I index, I index2, uint32_t depth) {
this->index = index;
this->index2 = index2;
this->depth = depth;
}
hypernode(I index, uint32_t depth) {
this->index = index;
this->index2 = 0;
this->depth = depth;
}
hypernode() {
this->index = -1;
this->index2 = 0;
this->depth = 0;
}
bool empty() const { return ((index == 0) && (index2 == 0)); }
bool nonempty() const { return ((index != 0) || (index2 != 0)); }
bool operator==(const hypernode<I> &other) const {
return ((depth == other.depth) && (index == other.index) && (index2 == other.index2));
}
};
template<typename I, int N, typename NV, typename LK, typename LV>
......@@ -104,7 +119,11 @@ namespace apg {
// Recursively mark node to rescue it from garbage-collection:
I gc_mark(hypernode<I> parent) {
if (parent.index == 0 || parent.index == ((I) -1)) {
if (parent.index2 != 0) {
gc_mark(hypernode<I>(parent.index2, parent.depth));
gc_mark(hypernode<I>(parent.index, parent.depth));
return 0;
} else if (parent.index == 0 || parent.index == ((I) -1)) {
return 0;
} else if (parent.depth == 0) {
kiventry<LK, I, LV>* pptr = leaves.ind2ptr(parent.index);
......
This diff is collapsed.
......@@ -74,7 +74,7 @@ namespace apg {
return threshold_gc(gc_threshold);
}
virtual kiventry<nicearray<I, 4>, I, lifemeta<I> >* ind2ptr_nonleaf(uint32_t depth, I index) = 0;
// virtual kiventry<nicearray<I, 4>, I, lifemeta<I> >* ind2ptr_nonleaf(uint32_t depth, I index) = 0;
virtual I make_nonleaf(uint32_t depth, nicearray<I, 4> contents) = 0;
virtual hypernode<I> make_nonleaf_hn(uint32_t depth, nicearray<I, 4> contents) = 0;
virtual I getpop_recurse(hypernode<I> hnode, I modprime, uint64_t layermask) = 0;
......@@ -83,32 +83,8 @@ namespace apg {
virtual hypernode<I> getchild(hypernode<I> hnode, uint32_t n) = 0;
virtual uint64_t leafpart(I index, uint32_t part) = 0;
hypernode<I> pyramid_down(hypernode<I> hnode) {
if (hnode.depth <= 1) { return hnode; }
if (hnode.index == 0) { return hypernode<I>(0, 1); }
// Extract the pointer for the node and its children:
kiventry<nicearray<I, 4>, I, lifemeta<I> >* pptr = ind2ptr_nonleaf(hnode.depth, hnode.index);
kiventry<nicearray<I, 4>, I, lifemeta<I> >* pptr_tl = ind2ptr_nonleaf(hnode.depth-1, pptr->key.x[0]);
kiventry<nicearray<I, 4>, I, lifemeta<I> >* pptr_tr = ind2ptr_nonleaf(hnode.depth-1, pptr->key.x[1]);
kiventry<nicearray<I, 4>, I, lifemeta<I> >* pptr_bl = ind2ptr_nonleaf(hnode.depth-1, pptr->key.x[2]);
kiventry<nicearray<I, 4>, I, lifemeta<I> >* pptr_br = ind2ptr_nonleaf(hnode.depth-1, pptr->key.x[3]);
bool tl_good = (pptr_tl->key.x[0] == 0) && (pptr_tl->key.x[1] == 0) && (pptr_tl->key.x[2] == 0);
bool tr_good = (pptr_tr->key.x[0] == 0) && (pptr_tr->key.x[1] == 0) && (pptr_tr->key.x[3] == 0);
bool bl_good = (pptr_bl->key.x[0] == 0) && (pptr_bl->key.x[2] == 0) && (pptr_bl->key.x[3] == 0);
bool br_good = (pptr_br->key.x[1] == 0) && (pptr_br->key.x[2] == 0) && (pptr_br->key.x[3] == 0);
if (tl_good && tr_good && bl_good && br_good) {
nicearray<I, 4> cc = {pptr_tl->key.x[3], pptr_tr->key.x[2], pptr_bl->key.x[1], pptr_br->key.x[0]};
hypernode<I> hncc = make_nonleaf_hn(hnode.depth-1, cc);
// Do this recursively:
return pyramid_down(hncc);
} else {
return hnode;
}
}
virtual hypernode<I> pyramid_down(hypernode<I> hnode) = 0;
virtual hypernode<I> pyramid_up(hypernode<I> hnode) = 0;
virtual hypernode<I> demorton_recurse(std::map<uint64_t, uint64_t>::iterator &it,
std::map<uint64_t, uint64_t>::iterator &pe,
......@@ -170,29 +146,6 @@ namespace apg {
return shift_recurse(xcc, ux, uy, sz);
}
hypernode<I> pyramid_up(hypernode<I> hnode) {
I z = 0;
if (hnode.depth == 0) {
nicearray<I, 4> cc = {z, z, z, hnode.index};
hypernode<I> hnode2 = make_nonleaf_hn(hnode.depth + 1, cc);
return shift_toroidal(hnode2, -1, -1, 3);
} else {
kiventry<nicearray<I, 4>, I, lifemeta<I> >* pptr = ind2ptr_nonleaf(hnode.depth, hnode.index);
nicearray<I, 4> tl = {z, z, z, pptr->key.x[0]};
nicearray<I, 4> tr = {z, z, pptr->key.x[1], z};
nicearray<I, 4> bl = {z, pptr->key.x[2], z, z};
nicearray<I, 4> br = {pptr->key.x[3], z, z, z};
nicearray<I, 4> nc = {make_nonleaf(hnode.depth, tl),
make_nonleaf(hnode.depth, tr),
make_nonleaf(hnode.depth, bl),
make_nonleaf(hnode.depth, br)};
return make_nonleaf_hn(hnode.depth + 1, nc);
}
}
hypernode<I> pyramid_up(hypernode<I> hnode_initial, uint32_t target_depth) {
hypernode<I> hnode = hnode_initial;
while (target_depth > hnode.depth) {
......@@ -233,6 +186,18 @@ namespace apg {
return boolean_recurse(lnode, rnode, operation, &memmap);
}
hypernode<I> breach(hypernode<I> hnode) {
if (hnode.index2 == 0) {
return hnode;
} else if (hnode.index == 0) {
return hypernode<I>(hnode.index2, hnode.depth);
} else {
hypernode<I> i1(hnode.index, hnode.depth);
hypernode<I> i2(hnode.index2, hnode.depth);
return boolean_recurse(i1, i2, 1);
}
}
hypernode<I> boolean_universe(hypernode<I> lnode, hypernode<I> rnode, int operation) {
hypernode<I> lx = lnode;
hypernode<I> rx = rnode;
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
#include "classifier.h"
#include "upattern.h"
#include "streamlife.h"
int main() {
apg::lifetree<uint32_t, 4> lt(1500);
apg::streamtree<uint32_t, 1> st(500);
/*
apg::pattern mkn(&lt, "16bo$15b2o$15bo3bo$14bo2bob2o$13b2o5bo$13bo2bo2bo$7bo5b2o4bo$7bobo5b2o"
"$7bobo6bo4$2o$obo$b2o$17b2o5b2ob3o$16bo3bo2b2ob2obo$16b2o5b2obob2o$17b"
"2o3bobo$17bo2bo$18bob2o4$6b3o$6bo19bo$7bo19bobo$29b2o$22b2o2bo4bo$22b"
......@@ -13,7 +16,7 @@ int main() {
std::cerr << mkn.apgcode() << std::endl;
return 0;
*/
apg::classifier c(&lt, "b3s23");
......@@ -58,6 +61,7 @@ int main() {
std::ofstream out("rubbish3.mc");
ip46.write_macrocell(out);
/*
apg::pattern y(&lt, "4b2o9b2o$3bobo9bobo$3bobob2o3b2obobo$b2o2bob2o3b2obo2b2o$o4bo9bo4bo$6o"
"b2o3b2ob6o$7bobobobo$2b2ob2o2bobo2b2ob2o$2b2obo3bobo3bob2o$6b3o3b3o2$"
"6b3o3b3o$2b2obo3bobo3bob2o$2b2ob2o2bobo2b2ob2o$7bobobobo$6ob2o3b2ob6o$"
......@@ -66,16 +70,32 @@ int main() {
std::vector<std::string> parts = c.pbbosc(y, 2, 4);
for (int i = 0; i < parts.size(); i++) { std::cerr << parts[i] << std::endl; }
*/
apg::pattern x(&lt, "bo$obo$bo8$8bo$6bobo$5b2obo2$4b3o!", "b3s23");
std::cerr << "Population of Lidka: " << x.popcount((1 << 30) + 3) << std::endl;
x = x["b3s23"][32768];
std::cerr << "Population of Lidka: " << x.popcount((1 << 30) + 3) << std::endl;
x = apg::pattern(&lt, "bo$obo$bo8$8bo$6bobo$5b2obo2$4b3o!", "r1b3t3s3t4");
std::cerr << "Population of Lidka: " << x.popcount((1 << 30) + 3) << std::endl;
x = x["r1b3t3s3t4"][32768];
std::cerr << "Population of Lidka: " << x.popcount((1 << 30) + 3) << std::endl;
/*
apg::pattern y(&st, "bo$obo$bo8$8bo$6bobo$5b2obo2$4b3o!", "b3s23");