@thi.ng/cellular 0.2.73 → 0.2.75
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/1d.js +221 -355
- package/CHANGELOG.md +1 -1
- package/README.md +1 -1
- package/api.js +0 -1
- package/package.json +13 -10
package/1d.js
CHANGED
|
@@ -12,369 +12,235 @@ import { transduce } from "@thi.ng/transducers/transduce";
|
|
|
12
12
|
const $0 = BigInt(0);
|
|
13
13
|
const $1 = BigInt(1);
|
|
14
14
|
const $32 = BigInt(32);
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
[-1, 0],
|
|
20
|
-
[0, 0],
|
|
21
|
-
[1, 0],
|
|
15
|
+
const WOLFRAM3 = [
|
|
16
|
+
[-1, 0],
|
|
17
|
+
[0, 0],
|
|
18
|
+
[1, 0]
|
|
22
19
|
];
|
|
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
|
-
* positions (for all non-zero cell states) to compute a summed ID:
|
|
85
|
-
*
|
|
86
|
-
* | k index | offset | cell value | encoded |
|
|
87
|
-
* |--------:|-----------|-----------:|--------:|
|
|
88
|
-
* | 0 | `[-2, 1]` | 2 | 1 |
|
|
89
|
-
* | 1 | `[-1, 0]` | 1 | 2 |
|
|
90
|
-
* | 2 | `[0, 0]` | 0 | 0 |
|
|
91
|
-
* | 3 | `[1, 0]` | 3 | 8 |
|
|
92
|
-
* | 4 | `[2, 1]` | 1 | 16 |
|
|
93
|
-
*
|
|
94
|
-
* Final encoded neighborhood sum: 1 + 2 + 8 + 16 = 27
|
|
95
|
-
*
|
|
96
|
-
* To determine if a the current cell should be active or not in the next
|
|
97
|
-
* generation, we now use that encoded sum as bit position to test a single bit
|
|
98
|
-
* of the automata's rule ID, i.e. here we're testing bit 27. If that
|
|
99
|
-
* corresponding bit is set in the rule ID, the cell's state will be increased
|
|
100
|
-
* by 1.
|
|
101
|
-
*
|
|
102
|
-
* ### Cell states
|
|
103
|
-
*
|
|
104
|
-
* Each automata config can define a max. number of possible cell states (aka
|
|
105
|
-
* age). Once a cell reaches the configured `numStates`, it automatically resets
|
|
106
|
-
* to zero. This is by default, but can be overridden via the
|
|
107
|
-
* {@link CASpec1D.reset} option. Conversely, if the corresponding bit is _not_
|
|
108
|
-
* set in the rule ID, the cell state will be zeroed too.
|
|
109
|
-
*
|
|
110
|
-
* ### Update probabilities
|
|
111
|
-
*
|
|
112
|
-
* Each cell has an optional update probability, which is initialized to 1.0 by
|
|
113
|
-
* default (i.e. to always be updated). Use
|
|
114
|
-
* {@link MultiCA1D.updateProbabilistic} or {@link MultiCA1D.updateImage} to
|
|
115
|
-
* take these probabilities into account.
|
|
116
|
-
*
|
|
117
|
-
* ### Wraparound
|
|
118
|
-
*
|
|
119
|
-
* By default the environment is configured to be toroidal, i.e. both left/right
|
|
120
|
-
* sides of the env are connected. The behavior can be controlled via a ctor arg
|
|
121
|
-
* and/or at runtime via the {@link MultiCA1D.wrap} property.
|
|
122
|
-
*
|
|
123
|
-
* ### Masks
|
|
124
|
-
*
|
|
125
|
-
* The {@link MultiCA1D.mask} array can be used to select different CA
|
|
126
|
-
* configurations for each cell in the environment. Because this mask array is
|
|
127
|
-
* initialized to zero, only the first CA configuration will be used for all
|
|
128
|
-
* cells in the environment by default. It's the user's responsibility to manage
|
|
129
|
-
* the mask and select/enable other (if any) CA configs for individual cells
|
|
130
|
-
* (usually cell ranges). The values stored in this array correspond to the
|
|
131
|
-
* indices of the {@link MultiCA1D.config} array given at construction.
|
|
132
|
-
*
|
|
133
|
-
* ### Limits
|
|
134
|
-
*
|
|
135
|
-
* Due to using `Uint8Arrays` for storage, only up to 256 cell states are
|
|
136
|
-
* supported. The same limit applies to the number of CA configs given.
|
|
137
|
-
*
|
|
138
|
-
* @example
|
|
139
|
-
* ```ts
|
|
140
|
-
* // classic Wolfram Rule 110 automata
|
|
141
|
-
* const wolfram = new MultiCA1D(
|
|
142
|
-
* [{
|
|
143
|
-
* kernel: [[-1, 0], [0, 0], [1, 0]],
|
|
144
|
-
* rule: 110,
|
|
145
|
-
* states: 2,
|
|
146
|
-
* reset: false
|
|
147
|
-
* }],
|
|
148
|
-
* 256
|
|
149
|
-
* )
|
|
150
|
-
* ```
|
|
151
|
-
*/
|
|
152
|
-
export class MultiCA1D {
|
|
153
|
-
width;
|
|
154
|
-
wrap;
|
|
155
|
-
configs;
|
|
156
|
-
rows;
|
|
157
|
-
numStates;
|
|
158
|
-
mask;
|
|
159
|
-
gens;
|
|
160
|
-
prob;
|
|
161
|
-
constructor(configs, width, wrap = true) {
|
|
162
|
-
this.width = width;
|
|
163
|
-
this.wrap = wrap;
|
|
164
|
-
this.configs = configs.map(__compileSpec);
|
|
165
|
-
this.rows =
|
|
166
|
-
transduce(mapcat((c) => map((k) => k[1], c.kernel)), max(), configs) + 1;
|
|
167
|
-
this.numStates = transduce(pluck("states"), max(), configs);
|
|
168
|
-
assert(this.numStates >= 2 && this.numStates <= 256, "num states must be in [2..256] range");
|
|
169
|
-
this.resize(width);
|
|
20
|
+
const WOLFRAM5 = [[-2, 0], ...WOLFRAM3, [2, 0]];
|
|
21
|
+
const WOLFRAM7 = [[-3, 0], ...WOLFRAM5, [3, 0]];
|
|
22
|
+
class MultiCA1D {
|
|
23
|
+
constructor(configs, width, wrap = true) {
|
|
24
|
+
this.width = width;
|
|
25
|
+
this.wrap = wrap;
|
|
26
|
+
this.configs = configs.map(__compileSpec);
|
|
27
|
+
this.rows = transduce(
|
|
28
|
+
mapcat((c) => map((k) => k[1], c.kernel)),
|
|
29
|
+
max(),
|
|
30
|
+
configs
|
|
31
|
+
) + 1;
|
|
32
|
+
this.numStates = transduce(pluck("states"), max(), configs);
|
|
33
|
+
assert(
|
|
34
|
+
this.numStates >= 2 && this.numStates <= 256,
|
|
35
|
+
"num states must be in [2..256] range"
|
|
36
|
+
);
|
|
37
|
+
this.resize(width);
|
|
38
|
+
}
|
|
39
|
+
configs;
|
|
40
|
+
rows;
|
|
41
|
+
numStates;
|
|
42
|
+
mask;
|
|
43
|
+
gens;
|
|
44
|
+
prob;
|
|
45
|
+
get current() {
|
|
46
|
+
return this.gens[1];
|
|
47
|
+
}
|
|
48
|
+
get previous() {
|
|
49
|
+
return this.gens[2 % this.gens.length];
|
|
50
|
+
}
|
|
51
|
+
clear() {
|
|
52
|
+
this.gens.forEach((g) => g.fill(0));
|
|
53
|
+
this.mask.fill(0);
|
|
54
|
+
this.prob.fill(1);
|
|
55
|
+
}
|
|
56
|
+
clearTarget(target) {
|
|
57
|
+
this._getTarget(target)[0].fill(target === "prob" ? 1 : 0);
|
|
58
|
+
}
|
|
59
|
+
resize(width) {
|
|
60
|
+
this.width = width;
|
|
61
|
+
this.mask = new Uint8Array(width);
|
|
62
|
+
this.gens = [...repeatedly(() => new Uint8Array(width), this.rows + 1)];
|
|
63
|
+
this.prob = new Float32Array(width).fill(1);
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Sets a parametric pattern in the current generation or mask array.
|
|
67
|
+
*
|
|
68
|
+
* @param target - target buffer ID to apply pattern
|
|
69
|
+
* @param width - number of consecutive cells per segment
|
|
70
|
+
* @param stride - number of cells between each pattern segment
|
|
71
|
+
* @param val - start cell value per segment
|
|
72
|
+
* @param inc - cell value increment
|
|
73
|
+
* @param offset - start cell offset
|
|
74
|
+
*/
|
|
75
|
+
setPattern(target, width, stride, val = 1, inc = 0, offset = 0) {
|
|
76
|
+
const [dest, num] = this._getTarget(target);
|
|
77
|
+
for (let x = offset, w = this.width; x < w; x += stride) {
|
|
78
|
+
for (let k = 0, v = val; k < width; k++, v += inc) {
|
|
79
|
+
dest[x + k] = v % num;
|
|
80
|
+
}
|
|
170
81
|
}
|
|
171
|
-
|
|
172
|
-
|
|
82
|
+
return this;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Sets cells in current generation array to a random state using given
|
|
86
|
+
* `probability` and optional PRNG
|
|
87
|
+
* ([`IRandom`](https://docs.thi.ng/umbrella/random/interfaces/IRandom.html)
|
|
88
|
+
* instance).
|
|
89
|
+
*
|
|
90
|
+
* @param target
|
|
91
|
+
* @param prob
|
|
92
|
+
* @param rnd
|
|
93
|
+
*/
|
|
94
|
+
setNoise(target, prob = 0.5, rnd = SYSTEM) {
|
|
95
|
+
const [dest, num] = this._getTarget(target);
|
|
96
|
+
const fn = target === "prob" ? () => rnd.float() : () => rnd.int() % num;
|
|
97
|
+
for (let x = 0, width = this.width; x < width; x++) {
|
|
98
|
+
if (rnd.probability(prob))
|
|
99
|
+
dest[x] = fn();
|
|
173
100
|
}
|
|
174
|
-
|
|
175
|
-
|
|
101
|
+
return this;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Computes a single new generation using current cell states and mask only
|
|
105
|
+
* (no consideration for cell update probabilities, use
|
|
106
|
+
* {@link MultiCA1D.updateProbabilistic} for that instead). Als see
|
|
107
|
+
* {@link MultiCA1D.updateImage} for batch updates.
|
|
108
|
+
*/
|
|
109
|
+
update() {
|
|
110
|
+
const { width, gens, configs, mask } = this;
|
|
111
|
+
const [next, curr] = gens;
|
|
112
|
+
for (let x = 0; x < width; x++) {
|
|
113
|
+
next[x] = this.computeCell(configs[mask[x]], x, curr[x]);
|
|
176
114
|
}
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
115
|
+
gens.unshift(gens.pop());
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Same as {@link MultiCA1D.update}, but also considering cell update
|
|
119
|
+
* probabilities stored in the {@link MultiCA1D.prob} array.
|
|
120
|
+
*
|
|
121
|
+
* @param rnd
|
|
122
|
+
*/
|
|
123
|
+
updateProbabilistic(rnd = SYSTEM) {
|
|
124
|
+
const { width, prob, gens, configs, mask } = this;
|
|
125
|
+
const [next, curr] = gens;
|
|
126
|
+
for (let x = 0; x < width; x++) {
|
|
127
|
+
next[x] = rnd.probability(prob[x]) ? this.computeCell(configs[mask[x]], x, curr[x]) : curr[x];
|
|
181
128
|
}
|
|
182
|
-
|
|
183
|
-
|
|
129
|
+
gens.unshift(gens.pop());
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Computes (but doesn't apply) the new state for a single cell.
|
|
133
|
+
*
|
|
134
|
+
* @param config - CA configuration
|
|
135
|
+
* @param x - cell index
|
|
136
|
+
* @param val - current cell value
|
|
137
|
+
*/
|
|
138
|
+
computeCell({ rule, kernel, weights, fn }, x, val) {
|
|
139
|
+
const { width, gens, wrap } = this;
|
|
140
|
+
let sum = $0;
|
|
141
|
+
for (let i = 0, n = kernel.length; i < n; i++) {
|
|
142
|
+
const k = kernel[i];
|
|
143
|
+
let xx = x + k[0];
|
|
144
|
+
if (wrap) {
|
|
145
|
+
if (xx < 0)
|
|
146
|
+
xx += width;
|
|
147
|
+
else if (xx >= width)
|
|
148
|
+
xx -= width;
|
|
149
|
+
} else if (xx < 0 || xx >= width)
|
|
150
|
+
continue;
|
|
151
|
+
const y = k[1];
|
|
152
|
+
if (y >= 0 && gens[1 + y][xx] !== 0)
|
|
153
|
+
sum += weights[i];
|
|
184
154
|
}
|
|
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
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
return this;
|
|
228
|
-
}
|
|
229
|
-
/**
|
|
230
|
-
* Computes a single new generation using current cell states and mask only
|
|
231
|
-
* (no consideration for cell update probabilities, use
|
|
232
|
-
* {@link MultiCA1D.updateProbabilistic} for that instead). Als see
|
|
233
|
-
* {@link MultiCA1D.updateImage} for batch updates.
|
|
234
|
-
*/
|
|
235
|
-
update() {
|
|
236
|
-
const { width, gens, configs, mask } = this;
|
|
237
|
-
const [next, curr] = gens;
|
|
238
|
-
for (let x = 0; x < width; x++) {
|
|
239
|
-
next[x] = this.computeCell(configs[mask[x]], x, curr[x]);
|
|
240
|
-
}
|
|
241
|
-
gens.unshift(gens.pop());
|
|
242
|
-
}
|
|
243
|
-
/**
|
|
244
|
-
* Same as {@link MultiCA1D.update}, but also considering cell update
|
|
245
|
-
* probabilities stored in the {@link MultiCA1D.prob} array.
|
|
246
|
-
*
|
|
247
|
-
* @param rnd
|
|
248
|
-
*/
|
|
249
|
-
updateProbabilistic(rnd = SYSTEM) {
|
|
250
|
-
const { width, prob, gens, configs, mask } = this;
|
|
251
|
-
const [next, curr] = gens;
|
|
252
|
-
for (let x = 0; x < width; x++) {
|
|
253
|
-
next[x] = rnd.probability(prob[x])
|
|
254
|
-
? this.computeCell(configs[mask[x]], x, curr[x])
|
|
255
|
-
: curr[x];
|
|
256
|
-
}
|
|
257
|
-
gens.unshift(gens.pop());
|
|
258
|
-
}
|
|
259
|
-
/**
|
|
260
|
-
* Computes (but doesn't apply) the new state for a single cell.
|
|
261
|
-
*
|
|
262
|
-
* @param config - CA configuration
|
|
263
|
-
* @param x - cell index
|
|
264
|
-
* @param val - current cell value
|
|
265
|
-
*/
|
|
266
|
-
computeCell({ rule, kernel, weights, fn }, x, val) {
|
|
267
|
-
const { width, gens, wrap } = this;
|
|
268
|
-
let sum = $0;
|
|
269
|
-
for (let i = 0, n = kernel.length; i < n; i++) {
|
|
270
|
-
const k = kernel[i];
|
|
271
|
-
let xx = x + k[0];
|
|
272
|
-
if (wrap) {
|
|
273
|
-
if (xx < 0)
|
|
274
|
-
xx += width;
|
|
275
|
-
else if (xx >= width)
|
|
276
|
-
xx -= width;
|
|
277
|
-
}
|
|
278
|
-
else if (xx < 0 || xx >= width)
|
|
279
|
-
continue;
|
|
280
|
-
const y = k[1];
|
|
281
|
-
if (y >= 0 && gens[1 + y][xx] !== 0)
|
|
282
|
-
sum += weights[i];
|
|
283
|
-
}
|
|
284
|
-
return rule & ($1 << sum) ? fn(val) : 0;
|
|
285
|
-
}
|
|
286
|
-
/**
|
|
287
|
-
* Batch version of {@link MultiCA1D.update} to compute an entire image of
|
|
288
|
-
* given `height` (and assumed to be the same width as this CA instance has
|
|
289
|
-
* been configured to). Fills given `pixels` array with consecutive
|
|
290
|
-
* generations.
|
|
291
|
-
*
|
|
292
|
-
* @remarks
|
|
293
|
-
* Via the provided options object, per-generation & per-cell perturbance
|
|
294
|
-
* settings can be provided for cell states, mask and cell update
|
|
295
|
-
* probabilities. The latter are only considered if the
|
|
296
|
-
* {@link UpdateImageOpts1D.probabilistic} option is enabled. This can be
|
|
297
|
-
* helpful to sporadically introduce noise into the sim, break constant
|
|
298
|
-
* patterns and/or produce more varied/complex outputs.
|
|
299
|
-
*
|
|
300
|
-
* See {@link UpdateImageOpts1D} for further options.
|
|
301
|
-
*
|
|
302
|
-
* @param pixels
|
|
303
|
-
* @param height
|
|
304
|
-
* @param opts
|
|
305
|
-
*/
|
|
306
|
-
updateImage(pixels, height, opts = {}) {
|
|
307
|
-
assert(pixels.length >= this.width * height, "target pixel buffer too small");
|
|
308
|
-
const { cells, mask, prob, probabilistic, rnd, onupdate } = {
|
|
309
|
-
probabilistic: false,
|
|
310
|
-
rnd: SYSTEM,
|
|
311
|
-
...opts,
|
|
312
|
-
};
|
|
313
|
-
const $ = (id, conf) => {
|
|
314
|
-
conf &&
|
|
315
|
-
conf.perturb &&
|
|
316
|
-
rnd.probability(conf.perturb) &&
|
|
317
|
-
this.setNoise(id, conf.density || 0.05, rnd);
|
|
318
|
-
};
|
|
319
|
-
for (let y = 0; y < height; y++) {
|
|
320
|
-
$("cells", cells);
|
|
321
|
-
$("mask", mask);
|
|
322
|
-
$("prob", prob);
|
|
323
|
-
probabilistic ? this.updateProbabilistic(rnd) : this.update();
|
|
324
|
-
onupdate && onupdate(this, y);
|
|
325
|
-
pixels.set(this.current, y * this.width);
|
|
326
|
-
}
|
|
327
|
-
}
|
|
328
|
-
rotate(target, dir) {
|
|
329
|
-
if (target === "all") {
|
|
330
|
-
rotateTyped(this.current, dir);
|
|
331
|
-
rotateTyped(this.mask, dir);
|
|
332
|
-
rotateTyped(this.prob, dir);
|
|
333
|
-
}
|
|
334
|
-
else {
|
|
335
|
-
rotateTyped(this._getTarget(target)[0], dir);
|
|
336
|
-
}
|
|
155
|
+
return rule & $1 << sum ? fn(val) : 0;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Batch version of {@link MultiCA1D.update} to compute an entire image of
|
|
159
|
+
* given `height` (and assumed to be the same width as this CA instance has
|
|
160
|
+
* been configured to). Fills given `pixels` array with consecutive
|
|
161
|
+
* generations.
|
|
162
|
+
*
|
|
163
|
+
* @remarks
|
|
164
|
+
* Via the provided options object, per-generation & per-cell perturbance
|
|
165
|
+
* settings can be provided for cell states, mask and cell update
|
|
166
|
+
* probabilities. The latter are only considered if the
|
|
167
|
+
* {@link UpdateImageOpts1D.probabilistic} option is enabled. This can be
|
|
168
|
+
* helpful to sporadically introduce noise into the sim, break constant
|
|
169
|
+
* patterns and/or produce more varied/complex outputs.
|
|
170
|
+
*
|
|
171
|
+
* See {@link UpdateImageOpts1D} for further options.
|
|
172
|
+
*
|
|
173
|
+
* @param pixels
|
|
174
|
+
* @param height
|
|
175
|
+
* @param opts
|
|
176
|
+
*/
|
|
177
|
+
updateImage(pixels, height, opts = {}) {
|
|
178
|
+
assert(
|
|
179
|
+
pixels.length >= this.width * height,
|
|
180
|
+
"target pixel buffer too small"
|
|
181
|
+
);
|
|
182
|
+
const { cells, mask, prob, probabilistic, rnd, onupdate } = {
|
|
183
|
+
probabilistic: false,
|
|
184
|
+
rnd: SYSTEM,
|
|
185
|
+
...opts
|
|
186
|
+
};
|
|
187
|
+
const $ = (id, conf) => {
|
|
188
|
+
conf && conf.perturb && rnd.probability(conf.perturb) && this.setNoise(id, conf.density || 0.05, rnd);
|
|
189
|
+
};
|
|
190
|
+
for (let y = 0; y < height; y++) {
|
|
191
|
+
$("cells", cells);
|
|
192
|
+
$("mask", mask);
|
|
193
|
+
$("prob", prob);
|
|
194
|
+
probabilistic ? this.updateProbabilistic(rnd) : this.update();
|
|
195
|
+
onupdate && onupdate(this, y);
|
|
196
|
+
pixels.set(this.current, y * this.width);
|
|
337
197
|
}
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
198
|
+
}
|
|
199
|
+
rotate(target, dir) {
|
|
200
|
+
if (target === "all") {
|
|
201
|
+
rotateTyped(this.current, dir);
|
|
202
|
+
rotateTyped(this.mask, dir);
|
|
203
|
+
rotateTyped(this.prob, dir);
|
|
204
|
+
} else {
|
|
205
|
+
rotateTyped(this._getTarget(target)[0], dir);
|
|
344
206
|
}
|
|
207
|
+
}
|
|
208
|
+
_getTarget(target) {
|
|
209
|
+
return target === "cells" ? [this.current, this.numStates] : target === "mask" ? [this.mask, this.configs.length] : [this.prob, 1];
|
|
210
|
+
}
|
|
345
211
|
}
|
|
346
|
-
const __compileSpec = ({
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
212
|
+
const __compileSpec = ({
|
|
213
|
+
rule,
|
|
214
|
+
kernel,
|
|
215
|
+
positional,
|
|
216
|
+
states,
|
|
217
|
+
reset
|
|
218
|
+
}) => {
|
|
219
|
+
const max2 = states - 1;
|
|
220
|
+
return {
|
|
221
|
+
kernel,
|
|
222
|
+
states,
|
|
223
|
+
rule: isBigInt(rule) ? rule : BigInt(rule),
|
|
224
|
+
weights: positional !== false ? kernel.map((_, i) => BigInt(2) ** BigInt(i)) : [...repeat($1, kernel.length)],
|
|
225
|
+
fn: reset !== false ? (y) => ++y >= states ? 0 : y : (y) => ++y >= max2 ? max2 : y
|
|
226
|
+
};
|
|
359
227
|
};
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
}
|
|
379
|
-
return id;
|
|
228
|
+
const randomRule1D = (kernelSize, rnd = SYSTEM) => {
|
|
229
|
+
const n = BigInt(2 ** kernelSize);
|
|
230
|
+
let id = $0;
|
|
231
|
+
for (let i = $0; i < n; i += $32) {
|
|
232
|
+
id <<= $32;
|
|
233
|
+
let mask = n - i;
|
|
234
|
+
if (mask > $32)
|
|
235
|
+
mask = $32;
|
|
236
|
+
id |= BigInt(rnd.int()) & ($1 << mask) - $1;
|
|
237
|
+
}
|
|
238
|
+
return id;
|
|
239
|
+
};
|
|
240
|
+
export {
|
|
241
|
+
MultiCA1D,
|
|
242
|
+
WOLFRAM3,
|
|
243
|
+
WOLFRAM5,
|
|
244
|
+
WOLFRAM7,
|
|
245
|
+
randomRule1D
|
|
380
246
|
};
|
package/CHANGELOG.md
CHANGED
package/README.md
CHANGED
package/api.js
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@thi.ng/cellular",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.75",
|
|
4
4
|
"description": "Highly customizable 1D cellular automata, shared env, multiple rules, arbitrary sized/shaped neighborhoods, short term memory, cell states etc.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"module": "./index.js",
|
|
@@ -24,7 +24,9 @@
|
|
|
24
24
|
"author": "Karsten Schmidt (https://thi.ng)",
|
|
25
25
|
"license": "Apache-2.0",
|
|
26
26
|
"scripts": {
|
|
27
|
-
"build": "yarn
|
|
27
|
+
"build": "yarn build:esbuild && yarn build:decl",
|
|
28
|
+
"build:decl": "tsc --declaration --emitDeclarationOnly",
|
|
29
|
+
"build:esbuild": "esbuild --format=esm --platform=neutral --target=es2022 --tsconfig=tsconfig.json --outdir=. src/**/*.ts",
|
|
28
30
|
"clean": "rimraf --glob '*.js' '*.d.ts' '*.map' doc",
|
|
29
31
|
"doc": "typedoc --excludePrivate --excludeInternal --out doc src/index.ts",
|
|
30
32
|
"doc:ae": "mkdir -p .ae/doc .ae/temp && api-extractor run --local --verbose",
|
|
@@ -33,15 +35,16 @@
|
|
|
33
35
|
"test": "bun test"
|
|
34
36
|
},
|
|
35
37
|
"dependencies": {
|
|
36
|
-
"@thi.ng/api": "^8.9.
|
|
37
|
-
"@thi.ng/arrays": "^2.7.
|
|
38
|
-
"@thi.ng/checks": "^3.4.
|
|
39
|
-
"@thi.ng/errors": "^2.4.
|
|
40
|
-
"@thi.ng/random": "^3.6.
|
|
41
|
-
"@thi.ng/transducers": "^8.8.
|
|
38
|
+
"@thi.ng/api": "^8.9.13",
|
|
39
|
+
"@thi.ng/arrays": "^2.7.9",
|
|
40
|
+
"@thi.ng/checks": "^3.4.13",
|
|
41
|
+
"@thi.ng/errors": "^2.4.7",
|
|
42
|
+
"@thi.ng/random": "^3.6.19",
|
|
43
|
+
"@thi.ng/transducers": "^8.8.16"
|
|
42
44
|
},
|
|
43
45
|
"devDependencies": {
|
|
44
46
|
"@microsoft/api-extractor": "^7.38.3",
|
|
47
|
+
"esbuild": "^0.19.8",
|
|
45
48
|
"rimraf": "^5.0.5",
|
|
46
49
|
"tools": "^0.0.1",
|
|
47
50
|
"typedoc": "^0.25.4",
|
|
@@ -67,7 +70,7 @@
|
|
|
67
70
|
"setTimeout": false
|
|
68
71
|
},
|
|
69
72
|
"engines": {
|
|
70
|
-
"node": ">=
|
|
73
|
+
"node": ">=18"
|
|
71
74
|
},
|
|
72
75
|
"files": [
|
|
73
76
|
"./*.js",
|
|
@@ -91,5 +94,5 @@
|
|
|
91
94
|
],
|
|
92
95
|
"year": 2022
|
|
93
96
|
},
|
|
94
|
-
"gitHead": "
|
|
97
|
+
"gitHead": "25a42a81fac8603a1e440a7aa8bc343276211ff4\n"
|
|
95
98
|
}
|