00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00025 #include "config.h"
00026 #include "Ca.h"
00027 #include "Color.h"
00028
00029 #ifndef BUILDING_DOX
00030 # include <iostream>
00031 #endif
00032
00033 #ifndef CA_CYCLIC_NEIGHBORHOOD
00034 # define CA_CYCLIC_NEIGHBORHOOD 0
00035 #endif
00036
00037 std::ostream& operator<< (std::ostream &str, const CaState &ca) {
00038 for (unsigned row = 0; row < ca.size(); ++row) {
00039 for (unsigned col = 0; col < ca.size(); ++col)
00040 str << " " << ca.getCellAtPos(Pos(row,col));
00041 str << std::endl;
00042 }
00043 return str;
00044 }
00045
00046 void writeRule(std::ostream &str, const TRule5N &rule) {
00047 static const unsigned CENTER = 1 << 0;
00048 static const unsigned TOP = 1 << 1;
00049 static const unsigned RIGHT = 1 << 2;
00050 static const unsigned BOTTOM = 1 << 3;
00051 static const unsigned LEFT = 1 << 4;
00052
00053
00054 str << " ";
00055 for (unsigned i = 0; i < RULE_WIDTH; ++i) {
00056 bool next = rule[i];
00057 if ((i & CENTER) == rule[i])
00058 continue;
00059 str << (next
00060 ? Color(C_LIGHT_GREEN)
00061 : Color(C_LIGHT_RED))
00062 << static_cast<bool>(i & TOP)
00063 << Color(C_NO_COLOR) << " ";
00064 }
00065 str << std::endl;
00066
00067
00068 for (unsigned i = 0; i < RULE_WIDTH; ++i) {
00069 bool next = rule[i];
00070 if ((i & CENTER) == rule[i])
00071 continue;
00072 str << (next
00073 ? Color(C_LIGHT_GREEN)
00074 : Color(C_LIGHT_RED))
00075 << static_cast<bool>(i & LEFT) << " "
00076 << static_cast<bool>(i & CENTER) << " "
00077 << static_cast<bool>(i & RIGHT) << " "
00078 << Color(C_NO_COLOR);
00079 }
00080 str << std::endl;
00081
00082
00083 str << " ";
00084 for (unsigned i = 0; i < RULE_WIDTH; ++i) {
00085 bool next = rule[i];
00086 if ((i & CENTER) == rule[i])
00087 continue;
00088 str << (next
00089 ? Color(C_LIGHT_GREEN)
00090 : Color(C_LIGHT_RED))
00091 << static_cast<bool>(i & BOTTOM)
00092 << Color(C_NO_COLOR) << " ";
00093 }
00094 str << std::endl;
00095 }
00096
00097 bool applyRule(const CaState &ca, Pos pos, const TRule5N &rule) {
00098 bool state = ca.getCellAtPos(pos);
00099
00100
00101 unsigned char idx = ca.getCellAtPos(neighbor(pos, D_LEFT));
00102 idx <<= 1; idx |= ca.getCellAtPos(neighbor(pos, D_BOTTOM));
00103 idx <<= 1; idx |= ca.getCellAtPos(neighbor(pos, D_RIGHT));
00104 idx <<= 1; idx |= ca.getCellAtPos(neighbor(pos, D_TOP));
00105 idx <<= 1; idx |= state;
00106
00107 #if DEBUG_RULE_APPLICATION
00108 std::cerr << std::endl;
00109 std::cerr << " "
00110 << static_cast<bool>(idx & (1 << 1))
00111 << std::endl;
00112 std::cerr << static_cast<bool>(idx & (1 << 4)) << " "
00113 << static_cast<bool>(idx & (1 << 0)) << " "
00114 << static_cast<bool>(idx & (1 << 2)) << std::endl;
00115 std::cerr << " " << static_cast<bool>(idx & (1 << 3))
00116 << std::endl << "--> " << rule[idx]
00117 << std::endl << std::endl;
00118 #endif // DEBUG_RULE_APPLICATION
00119
00120 return rule[idx];
00121 }
00122
00123 bool applyRules(CaState &ca, const ICaRules *rules) {
00124
00125 CaState last(ca);
00126
00127 for (unsigned row = 0; row < ca.size(); ++row) {
00128 for (unsigned col = 0; col < ca.size(); ++col) {
00129 const Pos pos(row, col);
00130 TRule5N rule;
00131 rules->getRuleAtPos(pos, rule);
00132 const bool nextState = applyRule(last, pos, rule);
00133 ca.setCellAtPos(pos, nextState);
00134 }
00135 }
00136
00137 return last != ca;
00138 }
00139
00140
00141
00142 CaState::CaState(size_t size):
00143 size_(size)
00144 {
00145 assert(size);
00146 bitset_.resize(size*size, false);
00147 }
00148
00149 size_t CaState::size() const {
00150 return size_;
00151 }
00152
00153 bool CaState::getCellAtPos(Pos pos) const {
00154 #if CA_CYCLIC_NEIGHBORHOOD
00155 if (-1 == pos.row)
00156 pos.row += size_;
00157 else if (static_cast<TCoord>(size_) == pos.row)
00158 pos.row = 0;
00159
00160 if (-1 == pos.col)
00161 pos.col += size_;
00162 else if (static_cast<TCoord>(size_) == pos.col)
00163 pos.col = 0;
00164 #endif
00165
00166 if (pos.row < 0 || pos.col < 0
00167 || size_ <= static_cast<size_t> (pos.row)
00168 || size_ <= static_cast<size_t> (pos.col))
00169 return false;
00170 else
00171 return bitset_[pos.row * size_ + pos.col];
00172 }
00173
00174 void CaState::setCellAtPos(Pos pos, bool val) {
00175 #if CA_CYCLIC_NEIGHBORHOOD
00176 if (-1 == pos.row)
00177 pos.row += size_;
00178 else if (static_cast<TCoord>(size_) == pos.row)
00179 pos.row = 0;
00180
00181 if (-1 == pos.col)
00182 pos.col += size_;
00183 else if (static_cast<TCoord>(size_) == pos.col)
00184 pos.col = 0;
00185 #endif
00186
00187 if (pos.row < 0 || pos.col < 0
00188 || size_ <= static_cast<size_t> (pos.row)
00189 || size_ <= static_cast<size_t> (pos.col))
00190 return;
00191 bitset_[pos.row * size_ + pos.col] = val;
00192 }
00193
00194 bool CaState::operator== (const CaState &other) const {
00195 return size_ == other.size_
00196 && bitset_ == other.bitset_;
00197 }
00198
00199
00200
00201 #ifndef BUILDING_DOX
00202 struct CaEvaluator::Private {
00203 IGate *gate;
00204 IGateBinding *binding;
00205 CaEvalParams params;
00206 };
00207 #endif
00208
00209 CaEvaluator::CaEvaluator(
00210 const IGate &gate,
00211 const IGateBinding &binding,
00212 const CaEvalParams ¶ms):
00213 d(new Private)
00214 {
00215 d->gate = gate.clone();
00216 d->binding = binding.clone();
00217 d->params = params;
00218 }
00219
00220 CaEvaluator::~CaEvaluator() {
00221 delete d->binding;
00222 delete d->gate;
00223 delete d;
00224 }
00225
00226 size_t CaEvaluator::caSize() const {
00227 return d->params.caSize;
00228 }
00229
00230 float CaEvaluator::eval(const ICaRules *ca) {
00231 const IGate &gate = *(d->gate);
00232 const IGateBinding &binding = *(d->binding);
00233 const TBus cnt = 1 << d->gate->nInputs();
00234 const unsigned nSteps = d->params.nSteps;
00235 unsigned score = 0;
00236
00237
00238 for(TBus in = 0; in < cnt; ++in) {
00239 const TBus exp = gate[in];
00240
00241
00242 CaState state(d->params.caSize);
00243 binding.setInput(state, in);
00244
00245 unsigned match = 0;
00246 for(unsigned step = 0; step < nSteps; ++step) {
00247
00248 bool live = applyRules(state, ca);
00249
00250
00251 TBus out = binding.getOutput(state);
00252 if (out == exp) {
00253 ++ match;
00254 } else {
00255
00256 const TBus nOut = d->gate->nOutputs();
00257 unsigned ham = 0;
00258 for (unsigned i = 0; i < nOut; ++i) {
00259 TBus mask = 1 << i;
00260 if (static_cast<bool>(out & mask) != static_cast<bool>(exp & mask))
00261 ++ ham;
00262 }
00263 match *= nOut - ham;
00264 match /= nOut;
00265 }
00266 if (!live) {
00267
00268 if (out == exp)
00269 match = nSteps << 1;
00270 else
00271 match <<= 1;
00272
00273
00274
00275
00276 break;
00277 }
00278 }
00279
00280
00281 score += match;
00282 }
00283
00284
00285 return static_cast<float>(score)/(cnt*(nSteps << 1));
00286 }
00287
00288 bool CaEvaluator::cntSteps(const ICaRules *ca, unsigned &min, unsigned &max) {
00289 const IGate &gate = *(d->gate);
00290 const IGateBinding &binding = *(d->binding);
00291 const TBus cnt = 1 << d->gate->nInputs();
00292 const unsigned maxSteps = d->params.nSteps;
00293 min = maxSteps;
00294 max = 0;
00295
00296
00297 for(TBus in = 0; in < cnt; ++in) {
00298 unsigned step;
00299
00300
00301 CaState state(d->params.caSize);
00302 binding.setInput(state, in);
00303
00304
00305 bool live = true;
00306 for(step = 0; live && step < maxSteps; ++step) {
00307 live = applyRules(state, ca);
00308 TBus out = binding.getOutput(state);
00309 TBus exp = gate[in];
00310 if (!live && out != exp)
00311 return false;
00312 }
00313
00314 if (live && step == maxSteps)
00315
00316 return false;
00317
00318
00319 if (step < min)
00320 min = step;
00321 if (max < step)
00322 max = step;
00323 }
00324
00325
00326 return true;
00327 }
00328
00329 namespace {
00330 void writeCaState(
00331 std::ostream &str,
00332 const CaState &state,
00333 const CaState &inputs,
00334 const CaState &outputs,
00335 const CaState &desiredOutputs,
00336 const CaState &lastState,
00337 bool preferInput = false)
00338 {
00339 const size_t size = state.size();
00340 assert(size == inputs.size());
00341 assert(size == outputs.size());
00342 assert(size == desiredOutputs.size());
00343 assert(size == lastState.size());
00344
00345 for (unsigned row = 0; row < size; ++row) {
00346 for (unsigned col = 0; col < size; ++col) {
00347 Pos pos(row, col);
00348
00349
00350 bool val = state.getCellAtPos(pos);
00351 bool in = inputs.getCellAtPos(pos);
00352 bool out = outputs.getCellAtPos(pos);
00353 bool outOk = out && (val == desiredOutputs.getCellAtPos(pos));
00354 bool change = val ^ lastState.getCellAtPos(pos);
00355
00356 str << " ";
00357
00358
00359 if (change)
00360 str << Color(C_YELLOW);
00361 else if (preferInput && in)
00362 str << Color(C_LIGHT_BLUE);
00363 else if (outOk)
00364 str << Color(C_LIGHT_GREEN);
00365 else if (out)
00366 str << Color(C_LIGHT_RED);
00367 else if (in)
00368 str << Color(C_LIGHT_GREEN);
00369
00370 str << val;
00371 if (in || out || change)
00372 str << Color(C_NO_COLOR);
00373 }
00374
00375
00376 str << std::endl;
00377 }
00378 }
00379 }
00380
00381 void CaEvaluator::simulate(const ICaRules *rules, std::ostream &str, TBus in) {
00382 const IGate &gate = *(d->gate);
00383 const IGateBinding &binding = *(d->binding);
00384 const size_t caSize = d->params.caSize;
00385 const unsigned maxSteps = d->params.nSteps;
00386
00387
00388 CaState inputs(caSize);
00389 binding.setInput(inputs, static_cast<TBus>(-1));
00390
00391
00392 CaState outputs(caSize);
00393 binding.setOutput(outputs, static_cast<TBus>(-1));
00394
00395
00396 CaState desiredOutputs(caSize);
00397 binding.setOutput(desiredOutputs, gate[in]);
00398
00399
00400 CaState state(caSize);
00401 binding.setInput(state, in);
00402 writeCaState(str, state, inputs, outputs, desiredOutputs, state, true);
00403 str << std::endl;
00404
00405
00406 bool live = true;
00407 for(unsigned step = 0; live && step < maxSteps; ++step) {
00408 CaState last(state);
00409 live = applyRules(state, rules);
00410 str << Color(C_LIGHT_BLUE) << "--- step: " << (step + 1)
00411 << Color(C_NO_COLOR) << std::endl;
00412 writeCaState(str, state, inputs, outputs, desiredOutputs, last);
00413 str << std::endl;
00414 }
00415 }
00416
00417 void CaEvaluator::simulate(const ICaRules *rules, std::ostream &str) {
00418 const TBus cnt = 1 << d->gate->nInputs();
00419
00420
00421 for(TBus in = 0; in < cnt; ++in) {
00422 str << Color(C_LIGHT_GREEN) << "--- input: " << in
00423 << Color(C_NO_COLOR) << std::endl;
00424 this->simulate(rules, str, in);
00425 }
00426 }
00427