1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214
|
#include <set>
#include <map>
#include <iostream>
#include <fstream>
#include <cstdio>
#include <stdlib.h>
#include "util.h"
#include "ruletable_algo.h"
using namespace std ;
const int MAXPARAMS = 9 ;
const int MAXSTATES = 256 ;
struct ndd {
int level, index ;
vector<int> vals ;
bool operator<(const ndd &n) const {
if (level != n.level)
return level < n.level ;
return vals < n.vals ;
}
bool operator==(const ndd &n) const {
return level == n.level && vals == n.vals ;
}
} ;
set<ndd> world ;
int nodeseq ;
int shrinksize = 100 ;
vector<ndd> seq ;
int n_states, neighborhood_size ;
int curndd = 0 ;
typedef unsigned char state ;
static int getnode(ndd &n) {
n.index = nodeseq ;
set<ndd>::iterator it = world.find(n) ;
if (it != world.end())
return it->index ;
seq.push_back(n) ;
world.insert(n) ;
return nodeseq++ ;
}
void initndd() {
curndd = -1 ;
for (int i=0; i<neighborhood_size; i++) {
ndd n ;
for (int j=0; j<n_states; j++)
n.vals.push_back(curndd) ;
n.level = i + 1 ;
curndd = getnode(n) ;
}
}
map<int, int> cache ;
int remap5[5] = {0, 3, 2, 4, 1} ;
int remap9[9] = {0, 5, 3, 7, 1, 4, 6, 2, 8} ;
int *remap ;
int addndd(const vector<vector<state> > &inputs, const state output,
int nddr, int at) {
if (at == 0)
return nddr < 0 ? output : nddr ;
map<int,int>::iterator it = cache.find(nddr) ;
if (it != cache.end())
return it->second ;
ndd n = seq[nddr] ;
const vector<state> &inset = inputs[remap[at-1]] ;
for (unsigned int i=0; i<inset.size(); i++)
n.vals[inset[i]] = addndd(inputs, output, n.vals[inset[i]], at-1) ;
return getnode(n) ;
}
void shrink() ;
void addndd(const vector<vector<state> > &inputs, const state output) {
if (neighborhood_size == 5)
remap = remap5 ;
else
remap = remap9 ;
cache.clear() ;
curndd = addndd(inputs, output, curndd, neighborhood_size) ;
if (nodeseq > shrinksize)
shrink() ;
}
int setdefaults(int nddr, int off, int at) {
if (at == 0)
return nddr < 0 ? off : nddr ;
map<int,int>::iterator it = cache.find(nddr) ;
if (it != cache.end())
return it->second ;
ndd n = seq[nddr] ;
for (int i=0; i<n_states; i++)
n.vals[i] = setdefaults(n.vals[i], i, at-1) ;
int r = getnode(n) ;
cache[nddr] = r ;
return r ;
}
void setdefaults() {
cache.clear() ;
curndd = setdefaults(curndd, -1, neighborhood_size) ;
}
/**
* Rebuilds the ndd from scratch.
*/
int recreate(const vector<ndd> &oseq, int nddr, int lev) {
if (lev == 0)
return nddr ;
map<int, int>::iterator it = cache.find(nddr) ;
if (it != cache.end())
return it->second ;
ndd n = oseq[nddr] ;
for (int i=0; i<n_states; i++)
n.vals[i] = recreate(oseq, n.vals[i], lev-1) ;
int r = getnode(n) ;
cache[nddr] = r ;
return r ;
}
void shrink() {
world.clear() ;
vector<ndd> oseq = seq ;
seq.clear() ;
cache.clear() ;
nodeseq = 0 ;
curndd = recreate(oseq, curndd, neighborhood_size) ;
cerr << "Shrunk from " << oseq.size() << " to " << seq.size() << endl ;
shrinksize = seq.size() * 2 ;
}
void write_ndd() {
shrink() ;
printf("num_states=%d\n", n_states) ;
printf("num_neighbors=%d\n", neighborhood_size-1) ;
printf("num_nodes=%d\n", (int)seq.size()) ;
for (unsigned int i=0; i<seq.size(); i++) {
printf("%d", seq[i].level) ;
for (unsigned int j=0; j<seq[i].vals.size(); j++)
printf(" %d", seq[i].vals[j]) ;
printf("\n") ;
}
}
class mylifeerrors : public lifeerrors {
public:
virtual void fatal(const char *s) {
fprintf(stderr, "%s\n", s) ;
exit(10) ;
}
virtual void warning(const char *s) {
fprintf(stderr, "%s\n", s) ;
}
virtual void status(const char *s) {
fprintf(stderr, "%s\n", s) ;
}
virtual void beginprogress(const char *) {
aborted = false ;
}
virtual bool abortprogress(double, const char *) {
return false ;
}
virtual void endprogress() {
// do nothing
}
virtual const char *getuserrules() {
return "" ;
}
virtual const char *getrulesdir() {
return "Rules/" ;
}
} mylifeerrors ;
class my_ruletable_algo : public ruletable_algo {
public:
my_ruletable_algo() : ruletable_algo() {}
string loadrule(string filename) {
return LoadRuleTable(filename) ;
}
void buildndd() ;
} ;
void my_ruletable_algo::buildndd() {
unsigned int iRule;
::n_states = n_states ;
::neighborhood_size = (neighborhood==vonNeumann ? 5 : 9) ;
initndd() ;
for(iRule=0;iRule<this->n_compressed_rules;iRule++) {
for (unsigned int bitno=0; bitno<sizeof(TBits)*8; bitno++) {
TBits bit = ((TBits)1)<<bitno ;
vector<vector<state> > in ;
int ok = 1 ;
for (int i=0; i<neighborhood_size; i++) {
vector<state> nv ;
for (unsigned int j=0; j<n_states; j++)
if (lut[i][j][iRule] & bit)
nv.push_back((state)j) ;
if (nv.size() == 0) {
ok = 0 ;
break ;
}
in.push_back(nv) ;
}
if (ok) {
state out = output[iRule*sizeof(TBits)*8+bitno] ;
addndd(in, out) ;
}
}
}
setdefaults() ;
shrink() ;
}
int main(int argc, char *argv[]) {
if (argc < 2) {
cerr << "Usage: RuleTableToTree rule >Rules/rule.tree" << endl ;
exit(0) ;
}
lifeerrors::seterrorhandler(&mylifeerrors) ;
my_ruletable_algo *rta = new my_ruletable_algo() ;
string err = rta->loadrule(argv[1]) ;
if (err.size() > 0) {
cerr << "Error: " << err << endl ;
exit(0) ;
}
rta->buildndd() ;
write_ndd() ;
delete rta ;
}
|