A (one dimensional) cellular automaton is a function1 F : Σ → Σ with the property that there is a K > 0 such that F (x)i depends only on the 2K + 1 coordinates xi−K , xi−K+1, . . . , xi−1, xi, xi+1, . . . , xi+K . A periodic point of σ is any x such that σ^p (x) = x for some p ∈ N, and a periodic point of F is any x such that F^q (x) = x for some q ∈ N. Given a cellular automaton F, a point x ∈ Σ is jointly periodic if there are p, q ∈ N such that σ^p (x) = F^q (x) = x, that is, it is a periodic point under both functions.
This project aims to explore the nature of one-dimensional Cellular Automata, in the hope of finding the structure of cellular automata through its periodic points.
License: MIT
ubuntu2004
/*1* Copyright (C) 2004 Bryant Lee2*3* This file is part of FPeriod.4*5* FPeriod is free software; you can redistribute it and/or modify6* it under the terms of the GNU General Public License as published by7* the Free Software Foundation; either version 2 of the License, or8* (at your option) any later version.9*10* FPeriod is distributed in the hope that it will be useful,11* but WITHOUT ANY WARRANTY; without even the implied warranty of12* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the13* GNU General Public License for more details.14*15* You should have received a copy of the GNU General Public License16* along with FPeriod; if not, write to the Free Software17* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA18*/1920/**21* Represents a polynomial function in terms x[-s,t] mod N22*23* Written by: Bryant Lee24* Date: 10/31/0425**/2627#include "Func.h"28#include "FuncNode.h"29#include "StringOps.h"3031#include <math.h> //for pow()3233#include <fstream> //for printing3435#include <string>36#include <list>3738//non-member function definitions39bool isDigit(char c);40list<FuncNode*>* deepCopyList(const list<FuncNode*> &inputList);41void printList(ofstream & fout, const list<FuncNode*> &inputList);42void clearFuncNodeList(list<FuncNode*> &inputList);4344extern int UINTSIZE;4546//constructor47Func::Func(const string & iStr, int iShiftSize, bool opt) {48unsigned int i = 0;49int tIndex = 0, tConst = 0;50string sub;5152//trim53str = iStr;54trim(str);5556//shiftsize57shiftSize = iShiftSize;5859if(str[0] == 't' || str[0] == 'T') { //table function60vector<string> subList;61unsigned int j;6263type = 0;6465split(str, ',', subList);6667subList[0] = subList[0].substr(2,subList[0].length() - 2); //remove "t("68trim(subList[0]);6970//get span71span = atoi(subList[0].c_str());72tablesize = (int) pow(shiftSize, span);7374//make the table75fTable = new int[tablesize];7677for(i = 0, j = 0; i < subList[1].length() && j < tablesize; i++) {78if(subList[1][i] != ' ' && subList[1][i] != '\t') {79fTable[j] = subList[1][i] - 48; //convert char to integer80j++;81}82}83}84else { //poly function85type = 1;86fTable = NULL;8788//special case: allow starting negative coefficient by prepending 089if(str[0] == '-')90str.insert(0,"0");9192//parse the string and make a list93while(i < str.length()) {94if(str[i] == 'x') { //term95unsigned int j = i + 1;96while(str[j] != '[') {97j++;98}99unsigned int k = j + 1;100while(str[k] != ']') {101k++;102}103sub = str.substr(j + 1, k - j - 1);104trim(sub);105tIndex = atoi(sub.c_str());106fList.push_back(new FuncNode(1, tIndex));107108i = k + 1; //ITERATE109}110else if(isDigit(str[i])) {111unsigned int j = i;112while(j < str.length() && isDigit(str[j])) {113j++;114}115sub = str.substr(i, j - i);116tConst = atoi(sub.c_str());117fList.push_back(new FuncNode(3, tConst));118119i = j; //ITERATE120}121else if(str[i] == '+' ||122str[i] == '-' ||123str[i] == '*' ||124str[i] == '^') {125int tOp = 0;126127switch(str[i]) {128case '+':129tOp = 1;130break;131case '-':132tOp = 2;133break;134case '*':135tOp = 3;136break;137case '^':138tOp = 4;139break;140default:141break;142}143144fList.push_back(new FuncNode(2, tOp));145146i++; //ITERATE147}148else {149//ignore unidentified characters150i++; //ITERATE151}152}153154if(opt) { //OPTIMIZED poly function155type = 2;156157//Make a list of all terms used in function158vector<int>::iterator new_end;159list<FuncNode*>::iterator it;160161//Find all terms162for(it = fList.begin(); it != fList.end(); it++) {163if((*it)->type == 1) {164optTerms.push_back((*it)->val);165}166}167168sort(optTerms.begin(), optTerms.end()); //sort169new_end = unique(optTerms.begin(),170optTerms.end()); //put duplicates at end171172optTerms.erase(new_end, optTerms.end()); //erase duplicates173174//Init optFindTerm175unsigned int numTerms = optTerms.size();176177//key = term #, val = coord in "compact" array178for(i = 0; i < numTerms; i++) {179optFindTerm.insert(pair<int,int>(optTerms[i], i));180}181182//DEBUG183/*184cout << "optFindTerm\n";185map<int,int>::const_iterator mit;186for(mit = optFindTerm.begin(); mit != optFindTerm.end(); mit++) {187cout << mit->first << " " << mit->second << "\n";188}189cout << "END optFindTerm\n";190*/191//END DEBUG192193//Create lookup table194byte itTerms[numTerms];195196//zero itTerms197for(i = 0; i < numTerms; i++)198itTerms[i] = 0;199200do {201optLookupMap.insert(pair<StorageKey, byte>(StorageKey(itTerms, numTerms),timage_by_inputs(itTerms, numTerms, optFindTerm)));202}while(!iterateWord(itTerms, numTerms, shiftSize));203204//DEBUG205/*206cout << "Lookup Map\n";207map<StorageKey,byte>::const_iterator mit;208for(mit = optLookupMap.begin(); mit != optLookupMap.end(); mit++) {209mit->first.print();210cout << " -> " << (int) mit->second << "\n";211}212cout << "END Lookup Map\n";213*/214//END DEBUG215}216}217}218219//destructor220Func::~Func() {221clearFuncNodeList(fList);222delete fTable;223}224225//put image of word x in output argument226void Func::image(byte *word, int wordLength, byte * output) {227int i;228229for(i = 0; i < wordLength; i++) {230output[i] = timage(word, wordLength, i);231}232}233234//put image of word x in output argument235//NOTE: the 4th parameter, blocks, can be derived from wordLength, but236//we avoid the division by passing it as a param.237void Func::image(unsigned int * word, int wordLength, unsigned int *output,238unsigned int blocks) {239int i;240241//zero output[]242for(i = 0; i < (int)blocks; i++) {243output[i] = 0;244}245246int blocki = 0, offseti = 0;247for(i = 0; i < wordLength; i++) {248output[blocki] |= (timage(word, wordLength, i) << offseti);249250offseti++;251if(offseti >= UINTSIZE) {252blocki++;253offseti -= UINTSIZE;254}255}256}257258//generates the index-th term of the image of x259byte Func::timage(byte *word, int wordLength, int index) {260byte ret = 0;261262if(type == 0) { //table function263unsigned int sum = 0, i, access;264265for(i = 0; i < span; i++) {266access = (index + i) % wordLength;267sum += word[access] * (int)pow(shiftSize, span - (i+1));268}269270ret = fTable[sum];271}272else if(type == 1) { //poly function273list<FuncNode*> *currList = deepCopyList(fList);274list<FuncNode*>::iterator it, pit, sit;275FuncNode *curr, *pre, *succ;276277//Perform ^278for(it = currList->begin(); it != currList->end(); it++) {279if((*it)->type == 2 && (*it)->val == 4) {280curr = *it;281282it--; //go to pre283pre = *it;284pit = it;285it++;286it++; //go to succ287succ = *it;288sit = it;289it--; //go to curr290291curr->type = 3;292curr->val = (int) pow(pre->termValue(word, wordLength, index),293succ->termValue(word, wordLength, index));294curr->val = curr->val % shiftSize;295296//no need to check for negative residual because power function297//cannot make a positive integer negative.298299//clean up300currList->erase(pit);301currList->erase(sit);302delete pre;303delete succ;304}305}306307//Perform *308for(it = currList->begin(); it != currList->end(); it++) {309if((*it)->type == 2 && (*it)->val == 3) {310curr = *it;311312it--; //go to pre313pre = *it;314pit = it;315it++;316it++; //go to succ317succ = *it;318sit = it;319it--; //go to curr320321curr->type = 3;322curr->val = (pre->termValue(word, wordLength, index) *323succ->termValue(word, wordLength, index)) % shiftSize;324325//no need to check for negative residual because *326//cannot make a positive integer negative.327328//clean up329currList->erase(pit);330currList->erase(sit);331delete pre;332delete succ;333}334}335336//Perform +/-337for(it = currList->begin(); it != currList->end(); it++) {338if((*it)->type == 2 && ((*it)->val == 1 || (*it)->val == 2)) {339curr = *it;340341it--; //go to pre342pre = *it;343pit = it;344it++;345it++; //go to succ346succ = *it;347sit = it;348it--; //go to curr349350curr->type = 3;351352if(curr->val == 2) { //perform -353curr->val = (pre->termValue(word, wordLength, index) -354succ->termValue(word, wordLength, index)) % shiftSize;355356//check for negative residual357if(curr->val < 0)358curr->val += shiftSize;359360}else { //curr.val == 1, perform +361curr->val = (pre->termValue(word, wordLength, index) +362succ->termValue(word, wordLength, index)) % shiftSize;363}364365//clean up366currList->erase(pit);367currList->erase(sit);368delete pre;369delete succ;370}371}372373//special case when F = x[j] for a single j and no operations374curr = *(currList->begin());375if(curr->type == 1) {376curr->val = curr->termValue(word, wordLength, index) % shiftSize;377if(curr->val < 0)378curr->val += shiftSize;379curr->type = 3;380}381382//We must capture the return value before we call383//clearFuncNodeList()384ret = curr->val;385386//DEBUG387//printList(*currList);388389//deletes the actual FuncNodes, not just their pointers390clearFuncNodeList(*currList);391392//delete the list393delete currList;394}395else { //type == 2, optimized poly396unsigned int numTerms = optTerms.size();397byte itTerms[numTerms];398unsigned int i; //iterator399int a; //temporary variable400401for(i = 0; i < numTerms; i++) {402a = (index + optTerms[i]) % wordLength;403404if(a < 0) {405a += wordLength; //adjust for c's negative residuals406}407408itTerms[i] = word[a];409}410411ret = optLookupMap.find(StorageKey(itTerms, numTerms))->second;412413//DEBUG414/*415cout << "Word: ";416printArray(word, wordLength);417cout << "Index: " << index << "\n";418cout << "itTerms: ";419printArray(itTerms, numTerms);420cout << "ret: " << ret << "\n";421*/422}423424return ret;425}426427//generates the index-th term of the image of x428unsigned int Func::timage(unsigned int *word, int wordLength, int index) {429unsigned int ret = 0;430431if(type == 0) { //table func432unsigned int sum = 0, i;433434int access;435int blocki, offseti;436access = index; //the actual index into the word437438blocki = index / UINTSIZE; //the block439440//the divide could also be done by while loop...441/*442blocki = 0; //the block443t1 = index - UINTSIZE;444while(t1 >= 0) {445blocki++;446t1 -= UINTSIZE;447}448*/449450//NOTE: this does offseti = index % UINTSIZE451offseti = index - UINTSIZE*blocki; //offset within the block452453for(i = 0; i < span; i++) {454if((word[blocki] >> (offseti)) & 1) {455sum |= (1 << (span - (i+1)));456}457458access++;459if(access >= wordLength) { //wrap-around to beginning of word460access = 0;461blocki = 0;462offseti = 0;463}464else {465offseti++;466if(offseti >= UINTSIZE) {467blocki++;468offseti = 0;469}470}471}472473ret = fTable[sum];474}475else if(type == 1){ //poly func476list<FuncNode*> *currList = deepCopyList(fList);477list<FuncNode*>::iterator it, pit, sit;478FuncNode *curr, *pre, *succ;479480//Perform ^481for(it = currList->begin(); it != currList->end(); it++) {482if((*it)->type == 2 && (*it)->val == 4) {483curr = *it;484485it--; //go to pre486pre = *it;487pit = it;488it++;489it++; //go to succ490succ = *it;491sit = it;492it--; //go to curr493494curr->type = 3;495curr->val = (int) pow(pre->termValue(word, wordLength, index),496succ->termValue(word, wordLength, index));497curr->val = curr->val % shiftSize;498499//no need to check for negative residual because power function500//cannot make a positive integer negative.501502//clean up503currList->erase(pit);504currList->erase(sit);505delete pre;506delete succ;507}508}509510//Perform *511for(it = currList->begin(); it != currList->end(); it++) {512if((*it)->type == 2 && (*it)->val == 3) {513curr = *it;514515it--; //go to pre516pre = *it;517pit = it;518it++;519it++; //go to succ520succ = *it;521sit = it;522it--; //go to curr523524curr->type = 3;525curr->val = (pre->termValue(word, wordLength, index) *526succ->termValue(word, wordLength, index)) % shiftSize;527528//no need to check for negative residual because *529//cannot make a positive integer negative.530531//clean up532currList->erase(pit);533currList->erase(sit);534delete pre;535delete succ;536}537}538539//Perform +/-540for(it = currList->begin(); it != currList->end(); it++) {541if((*it)->type == 2 && ((*it)->val == 1 || (*it)->val == 2)) {542curr = *it;543544it--; //go to pre545pre = *it;546pit = it;547it++;548it++; //go to succ549succ = *it;550sit = it;551it--; //go to curr552553curr->type = 3;554555if(curr->val == 2) { //perform -556curr->val = (pre->termValue(word, wordLength, index) -557succ->termValue(word, wordLength, index)) % shiftSize;558559//check for negative residual560if(curr->val < 0)561curr->val += shiftSize;562563}else { //curr.val == 1, perform +564curr->val = (pre->termValue(word, wordLength, index) +565succ->termValue(word, wordLength, index)) % shiftSize;566}567568//clean up569currList->erase(pit);570currList->erase(sit);571delete pre;572delete succ;573}574}575576//special case when F = x[j] for a single j and no operations577curr = *(currList->begin());578if(curr->type == 1) {579curr->val = curr->termValue(word, wordLength, index) % shiftSize;580if(curr->val < 0)581curr->val += shiftSize;582curr->type = 3;583}584585//We must capture the return value before we call586//clearFuncNodeList()587ret = curr->val;588589//DEBUG590//printList(*currList);591592//deletes the actual FuncNodes, not just their pointers593clearFuncNodeList(*currList);594595//delete the list596delete currList;597}598else { //type == 2, optimized poly599unsigned int numTerms = optTerms.size();600byte itTerms[numTerms];601unsigned int i; //iterator602int a; //temporary variable603604for(i = 0; i < numTerms; i++) {605a = (index + optTerms[i]) % wordLength;606607if(a < 0) {608a += wordLength; //adjust for c's negative residuals609}610611if(a < UINTSIZE) { // if a < UINTSIZE, avoid divide ops612itTerms[i] = (word[0] & (1 << a)) >> a;613}614else {615itTerms[i] = (word[a/UINTSIZE] & (1 << (a % UINTSIZE))) >> (a % UINTSIZE);616}617}618619ret = optLookupMap.find(StorageKey(itTerms, numTerms))->second;620621//DEBUG622/*623cout << "Word: ";624printArray(word, wordLength);625cout << "Index: " << index << "\n";626cout << "itTerms: ";627printArray(itTerms, numTerms);628cout << "ret: " << ret << "\n";629*/630}631632return ret;633}634635636void Func::print(ofstream & fout) {637if(type == 0) {638unsigned int i;639640fout << "(";641fout << span;642fout << ", ";643644for(i = 0; i < tablesize; i++) {645fout << fTable[i];646}647648fout << ")";649fout << "\n";650}651else {652printList(fout, fList);653}654}655656//deletes the FuncNodes (the ones pointed to by elements in list)657void clearFuncNodeList(list<FuncNode*> &inputList) {658list<FuncNode*>::iterator it;659660for(it = inputList.begin(); it != inputList.end(); it++) {661delete (*it);662}663}664665//print a list666void printList(ofstream & fout, const list<FuncNode*> &inputList) {667list<FuncNode*>::const_iterator it;668669for(it = inputList.begin(); it != inputList.end(); it++) {670(*it)->print(fout);671}672673fout << "\n";674}675676//deep copy the list677list<FuncNode*>* deepCopyList(const list<FuncNode*> &inputList) {678list<FuncNode*> *newList = new list<FuncNode*>;679list<FuncNode*>::const_iterator it;680681for(it = inputList.begin(); it != inputList.end(); it++) {682newList->push_back((*it)->deepCopy());683}684685return newList;686}687688//returns true if c is a digit689bool isDigit(char c) {690return (c >= 48 && c <= 57); //calculated by ascii691}692693// (used in opt polynomial functions only: for precomputing to lookup table)694// generates value of function based on inputs695byte Func::timage_by_inputs(byte *itTerms, int numTerms,696const map<int,int> &optFindTerm) {697byte ret = 0;698699list<FuncNode*> *currList = deepCopyList(fList);700list<FuncNode*>::iterator it, pit, sit;701FuncNode *curr, *pre, *succ;702703if(type == 0) {704cout << "ERROR: please terminate program\n";705}706else {707//Perform ^708for(it = currList->begin(); it != currList->end(); it++) {709if((*it)->type == 2 && (*it)->val == 4) {710curr = *it;711712it--; //go to pre713pre = *it;714pit = it;715it++;716it++; //go to succ717succ = *it;718sit = it;719it--; //go to curr720721curr->type = 3;722curr->val = (int) pow(pre->termValue_by_inputs(itTerms, numTerms, optFindTerm),723succ->termValue_by_inputs(itTerms, numTerms, optFindTerm));724curr->val = curr->val % shiftSize;725726//no need to check for negative residual because power function727//cannot make a positive integer negative.728729//clean up730currList->erase(pit);731currList->erase(sit);732delete pre;733delete succ;734}735}736737//Perform *738for(it = currList->begin(); it != currList->end(); it++) {739if((*it)->type == 2 && (*it)->val == 3) {740curr = *it;741742it--; //go to pre743pre = *it;744pit = it;745it++;746it++; //go to succ747succ = *it;748sit = it;749it--; //go to curr750751curr->type = 3;752curr->val = (pre->termValue_by_inputs(itTerms, numTerms, optFindTerm) *753succ->termValue_by_inputs(itTerms, numTerms, optFindTerm)) % shiftSize;754755//no need to check for negative residual because *756//cannot make a positive integer negative.757758//clean up759currList->erase(pit);760currList->erase(sit);761delete pre;762delete succ;763}764}765766//Perform +/-767for(it = currList->begin(); it != currList->end(); it++) {768if((*it)->type == 2 && ((*it)->val == 1 || (*it)->val == 2)) {769curr = *it;770771it--; //go to pre772pre = *it;773pit = it;774it++;775it++; //go to succ776succ = *it;777sit = it;778it--; //go to curr779780curr->type = 3;781782if(curr->val == 2) { //perform -783curr->val = (pre->termValue_by_inputs(itTerms, numTerms, optFindTerm) -784succ->termValue_by_inputs(itTerms, numTerms, optFindTerm)) % shiftSize;785786//check for negative residual787if(curr->val < 0)788curr->val += shiftSize;789790}else { //curr.val == 1, perform +791curr->val = (pre->termValue_by_inputs(itTerms, numTerms, optFindTerm) +792succ->termValue_by_inputs(itTerms, numTerms, optFindTerm)) % shiftSize;793}794795//clean up796currList->erase(pit);797currList->erase(sit);798delete pre;799delete succ;800}801}802803//special case when F = x[j] for a single j and no operations804curr = *(currList->begin());805if(curr->type == 1) {806curr->val = curr->termValue_by_inputs(itTerms, numTerms, optFindTerm) % shiftSize;807if(curr->val < 0)808curr->val += shiftSize;809curr->type = 3;810}811812//We must capture the return value before we call813//clearFuncNodeList()814ret = curr->val;815816//DEBUG817//printList(*currList);818819//deletes the actual FuncNodes, not just their pointers820clearFuncNodeList(*currList);821822//delete the list823delete currList;824}825826return ret;827}828829//return true if this is an opt function830bool Func::isOpt() {831return (type == 2);832}833834835836837838839840