Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download

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.

2034 views
License: MIT
ubuntu2004
1
/*
2
* Copyright (C) 2004 Bryant Lee
3
*
4
* This file is part of FPeriod.
5
*
6
* FPeriod is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation; either version 2 of the License, or
9
* (at your option) any later version.
10
*
11
* FPeriod is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
15
*
16
* You should have received a copy of the GNU General Public License
17
* along with FPeriod; if not, write to the Free Software
18
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19
*/
20
21
/**
22
* Represents a polynomial function in terms x[-s,t] mod N
23
*
24
* Written by: Bryant Lee
25
* Date: 10/31/04
26
**/
27
28
#include "Func.h"
29
#include "FuncNode.h"
30
#include "StringOps.h"
31
32
#include <math.h> //for pow()
33
34
#include <fstream> //for printing
35
36
#include <string>
37
#include <list>
38
39
//non-member function definitions
40
bool isDigit(char c);
41
list<FuncNode*>* deepCopyList(const list<FuncNode*> &inputList);
42
void printList(ofstream & fout, const list<FuncNode*> &inputList);
43
void clearFuncNodeList(list<FuncNode*> &inputList);
44
45
extern int UINTSIZE;
46
47
//constructor
48
Func::Func(const string & iStr, int iShiftSize, bool opt) {
49
unsigned int i = 0;
50
int tIndex = 0, tConst = 0;
51
string sub;
52
53
//trim
54
str = iStr;
55
trim(str);
56
57
//shiftsize
58
shiftSize = iShiftSize;
59
60
if(str[0] == 't' || str[0] == 'T') { //table function
61
vector<string> subList;
62
unsigned int j;
63
64
type = 0;
65
66
split(str, ',', subList);
67
68
subList[0] = subList[0].substr(2,subList[0].length() - 2); //remove "t("
69
trim(subList[0]);
70
71
//get span
72
span = atoi(subList[0].c_str());
73
tablesize = (int) pow(shiftSize, span);
74
75
//make the table
76
fTable = new int[tablesize];
77
78
for(i = 0, j = 0; i < subList[1].length() && j < tablesize; i++) {
79
if(subList[1][i] != ' ' && subList[1][i] != '\t') {
80
fTable[j] = subList[1][i] - 48; //convert char to integer
81
j++;
82
}
83
}
84
}
85
else { //poly function
86
type = 1;
87
fTable = NULL;
88
89
//special case: allow starting negative coefficient by prepending 0
90
if(str[0] == '-')
91
str.insert(0,"0");
92
93
//parse the string and make a list
94
while(i < str.length()) {
95
if(str[i] == 'x') { //term
96
unsigned int j = i + 1;
97
while(str[j] != '[') {
98
j++;
99
}
100
unsigned int k = j + 1;
101
while(str[k] != ']') {
102
k++;
103
}
104
sub = str.substr(j + 1, k - j - 1);
105
trim(sub);
106
tIndex = atoi(sub.c_str());
107
fList.push_back(new FuncNode(1, tIndex));
108
109
i = k + 1; //ITERATE
110
}
111
else if(isDigit(str[i])) {
112
unsigned int j = i;
113
while(j < str.length() && isDigit(str[j])) {
114
j++;
115
}
116
sub = str.substr(i, j - i);
117
tConst = atoi(sub.c_str());
118
fList.push_back(new FuncNode(3, tConst));
119
120
i = j; //ITERATE
121
}
122
else if(str[i] == '+' ||
123
str[i] == '-' ||
124
str[i] == '*' ||
125
str[i] == '^') {
126
int tOp = 0;
127
128
switch(str[i]) {
129
case '+':
130
tOp = 1;
131
break;
132
case '-':
133
tOp = 2;
134
break;
135
case '*':
136
tOp = 3;
137
break;
138
case '^':
139
tOp = 4;
140
break;
141
default:
142
break;
143
}
144
145
fList.push_back(new FuncNode(2, tOp));
146
147
i++; //ITERATE
148
}
149
else {
150
//ignore unidentified characters
151
i++; //ITERATE
152
}
153
}
154
155
if(opt) { //OPTIMIZED poly function
156
type = 2;
157
158
//Make a list of all terms used in function
159
vector<int>::iterator new_end;
160
list<FuncNode*>::iterator it;
161
162
//Find all terms
163
for(it = fList.begin(); it != fList.end(); it++) {
164
if((*it)->type == 1) {
165
optTerms.push_back((*it)->val);
166
}
167
}
168
169
sort(optTerms.begin(), optTerms.end()); //sort
170
new_end = unique(optTerms.begin(),
171
optTerms.end()); //put duplicates at end
172
173
optTerms.erase(new_end, optTerms.end()); //erase duplicates
174
175
//Init optFindTerm
176
unsigned int numTerms = optTerms.size();
177
178
//key = term #, val = coord in "compact" array
179
for(i = 0; i < numTerms; i++) {
180
optFindTerm.insert(pair<int,int>(optTerms[i], i));
181
}
182
183
//DEBUG
184
/*
185
cout << "optFindTerm\n";
186
map<int,int>::const_iterator mit;
187
for(mit = optFindTerm.begin(); mit != optFindTerm.end(); mit++) {
188
cout << mit->first << " " << mit->second << "\n";
189
}
190
cout << "END optFindTerm\n";
191
*/
192
//END DEBUG
193
194
//Create lookup table
195
byte itTerms[numTerms];
196
197
//zero itTerms
198
for(i = 0; i < numTerms; i++)
199
itTerms[i] = 0;
200
201
do {
202
optLookupMap.insert(pair<StorageKey, byte>(StorageKey(itTerms, numTerms),timage_by_inputs(itTerms, numTerms, optFindTerm)));
203
}while(!iterateWord(itTerms, numTerms, shiftSize));
204
205
//DEBUG
206
/*
207
cout << "Lookup Map\n";
208
map<StorageKey,byte>::const_iterator mit;
209
for(mit = optLookupMap.begin(); mit != optLookupMap.end(); mit++) {
210
mit->first.print();
211
cout << " -> " << (int) mit->second << "\n";
212
}
213
cout << "END Lookup Map\n";
214
*/
215
//END DEBUG
216
}
217
}
218
}
219
220
//destructor
221
Func::~Func() {
222
clearFuncNodeList(fList);
223
delete fTable;
224
}
225
226
//put image of word x in output argument
227
void Func::image(byte *word, int wordLength, byte * output) {
228
int i;
229
230
for(i = 0; i < wordLength; i++) {
231
output[i] = timage(word, wordLength, i);
232
}
233
}
234
235
//put image of word x in output argument
236
//NOTE: the 4th parameter, blocks, can be derived from wordLength, but
237
//we avoid the division by passing it as a param.
238
void Func::image(unsigned int * word, int wordLength, unsigned int *output,
239
unsigned int blocks) {
240
int i;
241
242
//zero output[]
243
for(i = 0; i < (int)blocks; i++) {
244
output[i] = 0;
245
}
246
247
int blocki = 0, offseti = 0;
248
for(i = 0; i < wordLength; i++) {
249
output[blocki] |= (timage(word, wordLength, i) << offseti);
250
251
offseti++;
252
if(offseti >= UINTSIZE) {
253
blocki++;
254
offseti -= UINTSIZE;
255
}
256
}
257
}
258
259
//generates the index-th term of the image of x
260
byte Func::timage(byte *word, int wordLength, int index) {
261
byte ret = 0;
262
263
if(type == 0) { //table function
264
unsigned int sum = 0, i, access;
265
266
for(i = 0; i < span; i++) {
267
access = (index + i) % wordLength;
268
sum += word[access] * (int)pow(shiftSize, span - (i+1));
269
}
270
271
ret = fTable[sum];
272
}
273
else if(type == 1) { //poly function
274
list<FuncNode*> *currList = deepCopyList(fList);
275
list<FuncNode*>::iterator it, pit, sit;
276
FuncNode *curr, *pre, *succ;
277
278
//Perform ^
279
for(it = currList->begin(); it != currList->end(); it++) {
280
if((*it)->type == 2 && (*it)->val == 4) {
281
curr = *it;
282
283
it--; //go to pre
284
pre = *it;
285
pit = it;
286
it++;
287
it++; //go to succ
288
succ = *it;
289
sit = it;
290
it--; //go to curr
291
292
curr->type = 3;
293
curr->val = (int) pow(pre->termValue(word, wordLength, index),
294
succ->termValue(word, wordLength, index));
295
curr->val = curr->val % shiftSize;
296
297
//no need to check for negative residual because power function
298
//cannot make a positive integer negative.
299
300
//clean up
301
currList->erase(pit);
302
currList->erase(sit);
303
delete pre;
304
delete succ;
305
}
306
}
307
308
//Perform *
309
for(it = currList->begin(); it != currList->end(); it++) {
310
if((*it)->type == 2 && (*it)->val == 3) {
311
curr = *it;
312
313
it--; //go to pre
314
pre = *it;
315
pit = it;
316
it++;
317
it++; //go to succ
318
succ = *it;
319
sit = it;
320
it--; //go to curr
321
322
curr->type = 3;
323
curr->val = (pre->termValue(word, wordLength, index) *
324
succ->termValue(word, wordLength, index)) % shiftSize;
325
326
//no need to check for negative residual because *
327
//cannot make a positive integer negative.
328
329
//clean up
330
currList->erase(pit);
331
currList->erase(sit);
332
delete pre;
333
delete succ;
334
}
335
}
336
337
//Perform +/-
338
for(it = currList->begin(); it != currList->end(); it++) {
339
if((*it)->type == 2 && ((*it)->val == 1 || (*it)->val == 2)) {
340
curr = *it;
341
342
it--; //go to pre
343
pre = *it;
344
pit = it;
345
it++;
346
it++; //go to succ
347
succ = *it;
348
sit = it;
349
it--; //go to curr
350
351
curr->type = 3;
352
353
if(curr->val == 2) { //perform -
354
curr->val = (pre->termValue(word, wordLength, index) -
355
succ->termValue(word, wordLength, index)) % shiftSize;
356
357
//check for negative residual
358
if(curr->val < 0)
359
curr->val += shiftSize;
360
361
}else { //curr.val == 1, perform +
362
curr->val = (pre->termValue(word, wordLength, index) +
363
succ->termValue(word, wordLength, index)) % shiftSize;
364
}
365
366
//clean up
367
currList->erase(pit);
368
currList->erase(sit);
369
delete pre;
370
delete succ;
371
}
372
}
373
374
//special case when F = x[j] for a single j and no operations
375
curr = *(currList->begin());
376
if(curr->type == 1) {
377
curr->val = curr->termValue(word, wordLength, index) % shiftSize;
378
if(curr->val < 0)
379
curr->val += shiftSize;
380
curr->type = 3;
381
}
382
383
//We must capture the return value before we call
384
//clearFuncNodeList()
385
ret = curr->val;
386
387
//DEBUG
388
//printList(*currList);
389
390
//deletes the actual FuncNodes, not just their pointers
391
clearFuncNodeList(*currList);
392
393
//delete the list
394
delete currList;
395
}
396
else { //type == 2, optimized poly
397
unsigned int numTerms = optTerms.size();
398
byte itTerms[numTerms];
399
unsigned int i; //iterator
400
int a; //temporary variable
401
402
for(i = 0; i < numTerms; i++) {
403
a = (index + optTerms[i]) % wordLength;
404
405
if(a < 0) {
406
a += wordLength; //adjust for c's negative residuals
407
}
408
409
itTerms[i] = word[a];
410
}
411
412
ret = optLookupMap.find(StorageKey(itTerms, numTerms))->second;
413
414
//DEBUG
415
/*
416
cout << "Word: ";
417
printArray(word, wordLength);
418
cout << "Index: " << index << "\n";
419
cout << "itTerms: ";
420
printArray(itTerms, numTerms);
421
cout << "ret: " << ret << "\n";
422
*/
423
}
424
425
return ret;
426
}
427
428
//generates the index-th term of the image of x
429
unsigned int Func::timage(unsigned int *word, int wordLength, int index) {
430
unsigned int ret = 0;
431
432
if(type == 0) { //table func
433
unsigned int sum = 0, i;
434
435
int access;
436
int blocki, offseti;
437
access = index; //the actual index into the word
438
439
blocki = index / UINTSIZE; //the block
440
441
//the divide could also be done by while loop...
442
/*
443
blocki = 0; //the block
444
t1 = index - UINTSIZE;
445
while(t1 >= 0) {
446
blocki++;
447
t1 -= UINTSIZE;
448
}
449
*/
450
451
//NOTE: this does offseti = index % UINTSIZE
452
offseti = index - UINTSIZE*blocki; //offset within the block
453
454
for(i = 0; i < span; i++) {
455
if((word[blocki] >> (offseti)) & 1) {
456
sum |= (1 << (span - (i+1)));
457
}
458
459
access++;
460
if(access >= wordLength) { //wrap-around to beginning of word
461
access = 0;
462
blocki = 0;
463
offseti = 0;
464
}
465
else {
466
offseti++;
467
if(offseti >= UINTSIZE) {
468
blocki++;
469
offseti = 0;
470
}
471
}
472
}
473
474
ret = fTable[sum];
475
}
476
else if(type == 1){ //poly func
477
list<FuncNode*> *currList = deepCopyList(fList);
478
list<FuncNode*>::iterator it, pit, sit;
479
FuncNode *curr, *pre, *succ;
480
481
//Perform ^
482
for(it = currList->begin(); it != currList->end(); it++) {
483
if((*it)->type == 2 && (*it)->val == 4) {
484
curr = *it;
485
486
it--; //go to pre
487
pre = *it;
488
pit = it;
489
it++;
490
it++; //go to succ
491
succ = *it;
492
sit = it;
493
it--; //go to curr
494
495
curr->type = 3;
496
curr->val = (int) pow(pre->termValue(word, wordLength, index),
497
succ->termValue(word, wordLength, index));
498
curr->val = curr->val % shiftSize;
499
500
//no need to check for negative residual because power function
501
//cannot make a positive integer negative.
502
503
//clean up
504
currList->erase(pit);
505
currList->erase(sit);
506
delete pre;
507
delete succ;
508
}
509
}
510
511
//Perform *
512
for(it = currList->begin(); it != currList->end(); it++) {
513
if((*it)->type == 2 && (*it)->val == 3) {
514
curr = *it;
515
516
it--; //go to pre
517
pre = *it;
518
pit = it;
519
it++;
520
it++; //go to succ
521
succ = *it;
522
sit = it;
523
it--; //go to curr
524
525
curr->type = 3;
526
curr->val = (pre->termValue(word, wordLength, index) *
527
succ->termValue(word, wordLength, index)) % shiftSize;
528
529
//no need to check for negative residual because *
530
//cannot make a positive integer negative.
531
532
//clean up
533
currList->erase(pit);
534
currList->erase(sit);
535
delete pre;
536
delete succ;
537
}
538
}
539
540
//Perform +/-
541
for(it = currList->begin(); it != currList->end(); it++) {
542
if((*it)->type == 2 && ((*it)->val == 1 || (*it)->val == 2)) {
543
curr = *it;
544
545
it--; //go to pre
546
pre = *it;
547
pit = it;
548
it++;
549
it++; //go to succ
550
succ = *it;
551
sit = it;
552
it--; //go to curr
553
554
curr->type = 3;
555
556
if(curr->val == 2) { //perform -
557
curr->val = (pre->termValue(word, wordLength, index) -
558
succ->termValue(word, wordLength, index)) % shiftSize;
559
560
//check for negative residual
561
if(curr->val < 0)
562
curr->val += shiftSize;
563
564
}else { //curr.val == 1, perform +
565
curr->val = (pre->termValue(word, wordLength, index) +
566
succ->termValue(word, wordLength, index)) % shiftSize;
567
}
568
569
//clean up
570
currList->erase(pit);
571
currList->erase(sit);
572
delete pre;
573
delete succ;
574
}
575
}
576
577
//special case when F = x[j] for a single j and no operations
578
curr = *(currList->begin());
579
if(curr->type == 1) {
580
curr->val = curr->termValue(word, wordLength, index) % shiftSize;
581
if(curr->val < 0)
582
curr->val += shiftSize;
583
curr->type = 3;
584
}
585
586
//We must capture the return value before we call
587
//clearFuncNodeList()
588
ret = curr->val;
589
590
//DEBUG
591
//printList(*currList);
592
593
//deletes the actual FuncNodes, not just their pointers
594
clearFuncNodeList(*currList);
595
596
//delete the list
597
delete currList;
598
}
599
else { //type == 2, optimized poly
600
unsigned int numTerms = optTerms.size();
601
byte itTerms[numTerms];
602
unsigned int i; //iterator
603
int a; //temporary variable
604
605
for(i = 0; i < numTerms; i++) {
606
a = (index + optTerms[i]) % wordLength;
607
608
if(a < 0) {
609
a += wordLength; //adjust for c's negative residuals
610
}
611
612
if(a < UINTSIZE) { // if a < UINTSIZE, avoid divide ops
613
itTerms[i] = (word[0] & (1 << a)) >> a;
614
}
615
else {
616
itTerms[i] = (word[a/UINTSIZE] & (1 << (a % UINTSIZE))) >> (a % UINTSIZE);
617
}
618
}
619
620
ret = optLookupMap.find(StorageKey(itTerms, numTerms))->second;
621
622
//DEBUG
623
/*
624
cout << "Word: ";
625
printArray(word, wordLength);
626
cout << "Index: " << index << "\n";
627
cout << "itTerms: ";
628
printArray(itTerms, numTerms);
629
cout << "ret: " << ret << "\n";
630
*/
631
}
632
633
return ret;
634
}
635
636
//print
637
void Func::print(ofstream & fout) {
638
if(type == 0) {
639
unsigned int i;
640
641
fout << "(";
642
fout << span;
643
fout << ", ";
644
645
for(i = 0; i < tablesize; i++) {
646
fout << fTable[i];
647
}
648
649
fout << ")";
650
fout << "\n";
651
}
652
else {
653
printList(fout, fList);
654
}
655
}
656
657
//deletes the FuncNodes (the ones pointed to by elements in list)
658
void clearFuncNodeList(list<FuncNode*> &inputList) {
659
list<FuncNode*>::iterator it;
660
661
for(it = inputList.begin(); it != inputList.end(); it++) {
662
delete (*it);
663
}
664
}
665
666
//print a list
667
void printList(ofstream & fout, const list<FuncNode*> &inputList) {
668
list<FuncNode*>::const_iterator it;
669
670
for(it = inputList.begin(); it != inputList.end(); it++) {
671
(*it)->print(fout);
672
}
673
674
fout << "\n";
675
}
676
677
//deep copy the list
678
list<FuncNode*>* deepCopyList(const list<FuncNode*> &inputList) {
679
list<FuncNode*> *newList = new list<FuncNode*>;
680
list<FuncNode*>::const_iterator it;
681
682
for(it = inputList.begin(); it != inputList.end(); it++) {
683
newList->push_back((*it)->deepCopy());
684
}
685
686
return newList;
687
}
688
689
//returns true if c is a digit
690
bool isDigit(char c) {
691
return (c >= 48 && c <= 57); //calculated by ascii
692
}
693
694
// (used in opt polynomial functions only: for precomputing to lookup table)
695
// generates value of function based on inputs
696
byte Func::timage_by_inputs(byte *itTerms, int numTerms,
697
const map<int,int> &optFindTerm) {
698
byte ret = 0;
699
700
list<FuncNode*> *currList = deepCopyList(fList);
701
list<FuncNode*>::iterator it, pit, sit;
702
FuncNode *curr, *pre, *succ;
703
704
if(type == 0) {
705
cout << "ERROR: please terminate program\n";
706
}
707
else {
708
//Perform ^
709
for(it = currList->begin(); it != currList->end(); it++) {
710
if((*it)->type == 2 && (*it)->val == 4) {
711
curr = *it;
712
713
it--; //go to pre
714
pre = *it;
715
pit = it;
716
it++;
717
it++; //go to succ
718
succ = *it;
719
sit = it;
720
it--; //go to curr
721
722
curr->type = 3;
723
curr->val = (int) pow(pre->termValue_by_inputs(itTerms, numTerms, optFindTerm),
724
succ->termValue_by_inputs(itTerms, numTerms, optFindTerm));
725
curr->val = curr->val % shiftSize;
726
727
//no need to check for negative residual because power function
728
//cannot make a positive integer negative.
729
730
//clean up
731
currList->erase(pit);
732
currList->erase(sit);
733
delete pre;
734
delete succ;
735
}
736
}
737
738
//Perform *
739
for(it = currList->begin(); it != currList->end(); it++) {
740
if((*it)->type == 2 && (*it)->val == 3) {
741
curr = *it;
742
743
it--; //go to pre
744
pre = *it;
745
pit = it;
746
it++;
747
it++; //go to succ
748
succ = *it;
749
sit = it;
750
it--; //go to curr
751
752
curr->type = 3;
753
curr->val = (pre->termValue_by_inputs(itTerms, numTerms, optFindTerm) *
754
succ->termValue_by_inputs(itTerms, numTerms, optFindTerm)) % shiftSize;
755
756
//no need to check for negative residual because *
757
//cannot make a positive integer negative.
758
759
//clean up
760
currList->erase(pit);
761
currList->erase(sit);
762
delete pre;
763
delete succ;
764
}
765
}
766
767
//Perform +/-
768
for(it = currList->begin(); it != currList->end(); it++) {
769
if((*it)->type == 2 && ((*it)->val == 1 || (*it)->val == 2)) {
770
curr = *it;
771
772
it--; //go to pre
773
pre = *it;
774
pit = it;
775
it++;
776
it++; //go to succ
777
succ = *it;
778
sit = it;
779
it--; //go to curr
780
781
curr->type = 3;
782
783
if(curr->val == 2) { //perform -
784
curr->val = (pre->termValue_by_inputs(itTerms, numTerms, optFindTerm) -
785
succ->termValue_by_inputs(itTerms, numTerms, optFindTerm)) % shiftSize;
786
787
//check for negative residual
788
if(curr->val < 0)
789
curr->val += shiftSize;
790
791
}else { //curr.val == 1, perform +
792
curr->val = (pre->termValue_by_inputs(itTerms, numTerms, optFindTerm) +
793
succ->termValue_by_inputs(itTerms, numTerms, optFindTerm)) % shiftSize;
794
}
795
796
//clean up
797
currList->erase(pit);
798
currList->erase(sit);
799
delete pre;
800
delete succ;
801
}
802
}
803
804
//special case when F = x[j] for a single j and no operations
805
curr = *(currList->begin());
806
if(curr->type == 1) {
807
curr->val = curr->termValue_by_inputs(itTerms, numTerms, optFindTerm) % shiftSize;
808
if(curr->val < 0)
809
curr->val += shiftSize;
810
curr->type = 3;
811
}
812
813
//We must capture the return value before we call
814
//clearFuncNodeList()
815
ret = curr->val;
816
817
//DEBUG
818
//printList(*currList);
819
820
//deletes the actual FuncNodes, not just their pointers
821
clearFuncNodeList(*currList);
822
823
//delete the list
824
delete currList;
825
}
826
827
return ret;
828
}
829
830
//return true if this is an opt function
831
bool Func::isOpt() {
832
return (type == 2);
833
}
834
835
836
837
838
839
840