@thi.ng/cellular 0.1.0 → 0.2.0
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.d.ts +46 -16
- package/1d.js +107 -39
- package/CHANGELOG.md +12 -1
- package/api.d.ts +51 -3
- package/package.json +5 -5
package/1d.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type { IClear, UIntArray } from "@thi.ng/api";
|
|
1
|
+
import type { IClear, TypedArray, UIntArray } from "@thi.ng/api";
|
|
2
2
|
import type { IRandom } from "@thi.ng/random";
|
|
3
|
-
import type { CAConfig1D, CASpec1D, Kernel, Target } from "./api.js";
|
|
3
|
+
import type { CAConfig1D, CASpec1D, Kernel, Target, UpdateImageOpts1D } from "./api.js";
|
|
4
4
|
/**
|
|
5
5
|
* Standard Wolfram automata 3-neighborhood (no history)
|
|
6
6
|
*/
|
|
@@ -92,6 +92,13 @@ export declare const WOLFRAM7: Kernel;
|
|
|
92
92
|
* {@link CASpec1D.reset} option. Conversely, if the corresponding bit is _not_
|
|
93
93
|
* set in the rule ID, the cell state will be zeroed too.
|
|
94
94
|
*
|
|
95
|
+
* ### Update probabilities
|
|
96
|
+
*
|
|
97
|
+
* Each cell has an optional update probability, which is initialized to 1.0 by
|
|
98
|
+
* default (i.e. to always be updated). Use
|
|
99
|
+
* {@link MultiCA1D.updateProbabilistic} or {@link MultiCA1D.updateImage} to
|
|
100
|
+
* take these probabilities into account.
|
|
101
|
+
*
|
|
95
102
|
* ### Wraparound
|
|
96
103
|
*
|
|
97
104
|
* By default the environment is configured to be toroidal, i.e. both left/right
|
|
@@ -135,11 +142,12 @@ export declare class MultiCA1D implements IClear {
|
|
|
135
142
|
numStates: number;
|
|
136
143
|
mask: Uint8Array;
|
|
137
144
|
gens: Uint8Array[];
|
|
145
|
+
prob: Float32Array;
|
|
138
146
|
constructor(configs: CASpec1D[], width: number, wrap?: boolean);
|
|
139
147
|
get current(): Uint8Array;
|
|
140
148
|
get previous(): Uint8Array;
|
|
141
149
|
clear(): void;
|
|
142
|
-
|
|
150
|
+
clearTarget(target: Target): void;
|
|
143
151
|
resize(width: number): void;
|
|
144
152
|
/**
|
|
145
153
|
* Sets a parametric pattern in the current generation or mask array.
|
|
@@ -162,28 +170,50 @@ export declare class MultiCA1D implements IClear {
|
|
|
162
170
|
*/
|
|
163
171
|
setNoise(target: Target, prob?: number, rnd?: IRandom): this;
|
|
164
172
|
/**
|
|
165
|
-
* Computes a single new generation using current cell states and mask
|
|
173
|
+
* Computes a single new generation using current cell states and mask only
|
|
174
|
+
* (no consideration for cell update probabilities, use
|
|
175
|
+
* {@link MultiCA1D.updateProbabilistic} for that instead). Als see
|
|
166
176
|
* {@link MultiCA1D.updateImage} for batch updates.
|
|
167
177
|
*/
|
|
168
178
|
update(): void;
|
|
179
|
+
/**
|
|
180
|
+
* Same as {@link MultiCA1D.update}, but also considering cell update
|
|
181
|
+
* probabilities stored in the {@link MultiCA1D.prob} array.
|
|
182
|
+
*
|
|
183
|
+
* @param rnd
|
|
184
|
+
*/
|
|
185
|
+
updateProbabilistic(rnd?: IRandom): void;
|
|
186
|
+
/**
|
|
187
|
+
* Computes (but doesn't apply) the new state for a single cell.
|
|
188
|
+
*
|
|
189
|
+
* @param config - CA configuration
|
|
190
|
+
* @param x - cell index
|
|
191
|
+
* @param val - current cell value
|
|
192
|
+
*/
|
|
193
|
+
computeCell({ rule, kernel, weights, fn }: CAConfig1D, x: number, val: number): number;
|
|
169
194
|
/**
|
|
170
195
|
* Batch version of {@link MultiCA1D.update} to compute an entire image of
|
|
171
|
-
* given `height` (and same width as this CA instance has
|
|
172
|
-
* to).
|
|
173
|
-
*
|
|
174
|
-
*
|
|
175
|
-
*
|
|
176
|
-
*
|
|
196
|
+
* given `height` (and assumed to be the same width as this CA instance has
|
|
197
|
+
* been configured to). Fills given `pixels` array with consecutive
|
|
198
|
+
* generations.
|
|
199
|
+
*
|
|
200
|
+
* @remarks
|
|
201
|
+
* Via the provided options object, per-generation & per-cell perturbance
|
|
202
|
+
* settings can be provided for cell states, mask and cell update
|
|
203
|
+
* probabilities. The latter are only considered if the
|
|
204
|
+
* {@link UpdateImageOpts1D.probabilistic} option is enabled. This can be
|
|
205
|
+
* helpful to sporadically introduce noise into the sim, break constant
|
|
206
|
+
* patterns and/or produce more varied/complex outputs.
|
|
207
|
+
*
|
|
208
|
+
* See {@link UpdateImageOpts1D} for further options.
|
|
177
209
|
*
|
|
178
210
|
* @param pixels
|
|
179
211
|
* @param height
|
|
180
|
-
* @param
|
|
181
|
-
* @param density
|
|
182
|
-
* @param rnd
|
|
212
|
+
* @param opts
|
|
183
213
|
*/
|
|
184
|
-
updateImage(pixels: UIntArray, height: number,
|
|
185
|
-
rotate(dir: number): void;
|
|
186
|
-
protected _getTarget(target: Target): [
|
|
214
|
+
updateImage(pixels: UIntArray, height: number, opts?: Partial<UpdateImageOpts1D>): void;
|
|
215
|
+
rotate(target: Target | "all", dir: number): void;
|
|
216
|
+
protected _getTarget(target: Target): [TypedArray, number];
|
|
187
217
|
}
|
|
188
218
|
/**
|
|
189
219
|
* Creates a random rule ID for given `kernelSize` and using optionally provided
|
package/1d.js
CHANGED
|
@@ -106,6 +106,13 @@ export const WOLFRAM7 = [[-3, 0], ...WOLFRAM5, [3, 0]];
|
|
|
106
106
|
* {@link CASpec1D.reset} option. Conversely, if the corresponding bit is _not_
|
|
107
107
|
* set in the rule ID, the cell state will be zeroed too.
|
|
108
108
|
*
|
|
109
|
+
* ### Update probabilities
|
|
110
|
+
*
|
|
111
|
+
* Each cell has an optional update probability, which is initialized to 1.0 by
|
|
112
|
+
* default (i.e. to always be updated). Use
|
|
113
|
+
* {@link MultiCA1D.updateProbabilistic} or {@link MultiCA1D.updateImage} to
|
|
114
|
+
* take these probabilities into account.
|
|
115
|
+
*
|
|
109
116
|
* ### Wraparound
|
|
110
117
|
*
|
|
111
118
|
* By default the environment is configured to be toroidal, i.e. both left/right
|
|
@@ -160,14 +167,17 @@ export class MultiCA1D {
|
|
|
160
167
|
}
|
|
161
168
|
clear() {
|
|
162
169
|
this.gens.forEach((g) => g.fill(0));
|
|
170
|
+
this.mask.fill(0);
|
|
171
|
+
this.prob.fill(1);
|
|
163
172
|
}
|
|
164
|
-
|
|
165
|
-
this.
|
|
173
|
+
clearTarget(target) {
|
|
174
|
+
this._getTarget(target)[0].fill(target === "prob" ? 1 : 0);
|
|
166
175
|
}
|
|
167
176
|
resize(width) {
|
|
168
177
|
this.width = width;
|
|
169
178
|
this.mask = new Uint8Array(width);
|
|
170
179
|
this.gens = [...repeatedly(() => new Uint8Array(width), this.rows + 1)];
|
|
180
|
+
this.prob = new Float32Array(width).fill(1);
|
|
171
181
|
}
|
|
172
182
|
/**
|
|
173
183
|
* Sets a parametric pattern in the current generation or mask array.
|
|
@@ -198,71 +208,129 @@ export class MultiCA1D {
|
|
|
198
208
|
*/
|
|
199
209
|
setNoise(target, prob = 0.5, rnd = SYSTEM) {
|
|
200
210
|
const [dest, num] = this._getTarget(target);
|
|
211
|
+
const fn = target === "prob" ? () => rnd.float() : () => rnd.int() % num;
|
|
201
212
|
for (let x = 0, width = this.width; x < width; x++) {
|
|
202
213
|
if (rnd.float() < prob)
|
|
203
|
-
dest[x] =
|
|
214
|
+
dest[x] = fn();
|
|
204
215
|
}
|
|
205
216
|
return this;
|
|
206
217
|
}
|
|
207
218
|
/**
|
|
208
|
-
* Computes a single new generation using current cell states and mask
|
|
219
|
+
* Computes a single new generation using current cell states and mask only
|
|
220
|
+
* (no consideration for cell update probabilities, use
|
|
221
|
+
* {@link MultiCA1D.updateProbabilistic} for that instead). Als see
|
|
209
222
|
* {@link MultiCA1D.updateImage} for batch updates.
|
|
210
223
|
*/
|
|
211
224
|
update() {
|
|
212
|
-
const { width, gens, configs, mask
|
|
225
|
+
const { width, gens, configs, mask } = this;
|
|
213
226
|
const [next, curr] = gens;
|
|
214
227
|
for (let x = 0; x < width; x++) {
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
228
|
+
next[x] = this.computeCell(configs[mask[x]], x, curr[x]);
|
|
229
|
+
}
|
|
230
|
+
gens.unshift(gens.pop());
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Same as {@link MultiCA1D.update}, but also considering cell update
|
|
234
|
+
* probabilities stored in the {@link MultiCA1D.prob} array.
|
|
235
|
+
*
|
|
236
|
+
* @param rnd
|
|
237
|
+
*/
|
|
238
|
+
updateProbabilistic(rnd = SYSTEM) {
|
|
239
|
+
const { width, prob, gens, configs, mask } = this;
|
|
240
|
+
const [next, curr] = gens;
|
|
241
|
+
for (let x = 0; x < width; x++) {
|
|
242
|
+
next[x] =
|
|
243
|
+
rnd.float() < prob[x]
|
|
244
|
+
? this.computeCell(configs[mask[x]], x, curr[x])
|
|
245
|
+
: curr[x];
|
|
233
246
|
}
|
|
234
247
|
gens.unshift(gens.pop());
|
|
235
248
|
}
|
|
249
|
+
/**
|
|
250
|
+
* Computes (but doesn't apply) the new state for a single cell.
|
|
251
|
+
*
|
|
252
|
+
* @param config - CA configuration
|
|
253
|
+
* @param x - cell index
|
|
254
|
+
* @param val - current cell value
|
|
255
|
+
*/
|
|
256
|
+
computeCell({ rule, kernel, weights, fn }, x, val) {
|
|
257
|
+
const { width, gens, wrap } = this;
|
|
258
|
+
let sum = $0;
|
|
259
|
+
for (let i = 0, n = kernel.length; i < n; i++) {
|
|
260
|
+
const k = kernel[i];
|
|
261
|
+
let xx = x + k[0];
|
|
262
|
+
if (wrap) {
|
|
263
|
+
if (xx < 0)
|
|
264
|
+
xx += width;
|
|
265
|
+
else if (xx >= width)
|
|
266
|
+
xx -= width;
|
|
267
|
+
}
|
|
268
|
+
else if (xx < 0 || xx >= width)
|
|
269
|
+
continue;
|
|
270
|
+
const y = k[1];
|
|
271
|
+
if (y >= 0 && gens[1 + y][xx] !== 0)
|
|
272
|
+
sum += weights[i];
|
|
273
|
+
}
|
|
274
|
+
return rule & ($1 << sum) ? fn(val) : 0;
|
|
275
|
+
}
|
|
236
276
|
/**
|
|
237
277
|
* Batch version of {@link MultiCA1D.update} to compute an entire image of
|
|
238
|
-
* given `height` (and same width as this CA instance has
|
|
239
|
-
* to).
|
|
240
|
-
*
|
|
241
|
-
*
|
|
242
|
-
*
|
|
243
|
-
*
|
|
278
|
+
* given `height` (and assumed to be the same width as this CA instance has
|
|
279
|
+
* been configured to). Fills given `pixels` array with consecutive
|
|
280
|
+
* generations.
|
|
281
|
+
*
|
|
282
|
+
* @remarks
|
|
283
|
+
* Via the provided options object, per-generation & per-cell perturbance
|
|
284
|
+
* settings can be provided for cell states, mask and cell update
|
|
285
|
+
* probabilities. The latter are only considered if the
|
|
286
|
+
* {@link UpdateImageOpts1D.probabilistic} option is enabled. This can be
|
|
287
|
+
* helpful to sporadically introduce noise into the sim, break constant
|
|
288
|
+
* patterns and/or produce more varied/complex outputs.
|
|
289
|
+
*
|
|
290
|
+
* See {@link UpdateImageOpts1D} for further options.
|
|
244
291
|
*
|
|
245
292
|
* @param pixels
|
|
246
293
|
* @param height
|
|
247
|
-
* @param
|
|
248
|
-
* @param density
|
|
249
|
-
* @param rnd
|
|
294
|
+
* @param opts
|
|
250
295
|
*/
|
|
251
|
-
updateImage(pixels, height,
|
|
296
|
+
updateImage(pixels, height, opts = {}) {
|
|
297
|
+
assert(pixels.length >= this.width * height, "target pixel buffer too small");
|
|
298
|
+
const { cells, mask, prob, probabilistic, rnd, onupdate } = {
|
|
299
|
+
probabilistic: false,
|
|
300
|
+
rnd: SYSTEM,
|
|
301
|
+
...opts,
|
|
302
|
+
};
|
|
303
|
+
const $ = (id, conf) => {
|
|
304
|
+
conf &&
|
|
305
|
+
conf.perturb &&
|
|
306
|
+
rnd.float() < conf.perturb &&
|
|
307
|
+
this.setNoise(id, conf.density || 0.05, rnd);
|
|
308
|
+
};
|
|
252
309
|
for (let y = 0; y < height; y++) {
|
|
253
|
-
|
|
254
|
-
|
|
310
|
+
$("cells", cells);
|
|
311
|
+
$("mask", mask);
|
|
312
|
+
$("prob", prob);
|
|
313
|
+
probabilistic ? this.updateProbabilistic(rnd) : this.update();
|
|
314
|
+
onupdate && onupdate(this, y);
|
|
255
315
|
pixels.set(this.current, y * this.width);
|
|
256
316
|
}
|
|
257
317
|
}
|
|
258
|
-
rotate(dir) {
|
|
259
|
-
|
|
260
|
-
|
|
318
|
+
rotate(target, dir) {
|
|
319
|
+
if (target === "all") {
|
|
320
|
+
__rotate(this.current, dir);
|
|
321
|
+
__rotate(this.mask, dir);
|
|
322
|
+
__rotate(this.prob, dir);
|
|
323
|
+
}
|
|
324
|
+
else {
|
|
325
|
+
__rotate(this._getTarget(target)[0], dir);
|
|
326
|
+
}
|
|
261
327
|
}
|
|
262
328
|
_getTarget(target) {
|
|
263
329
|
return target === "cells"
|
|
264
330
|
? [this.current, this.numStates]
|
|
265
|
-
:
|
|
331
|
+
: target === "mask"
|
|
332
|
+
? [this.mask, this.configs.length]
|
|
333
|
+
: [this.prob, 1];
|
|
266
334
|
}
|
|
267
335
|
}
|
|
268
336
|
const __compileSpec = ({ rule, kernel, positional, states, reset, }) => {
|
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Change Log
|
|
2
2
|
|
|
3
|
-
- **Last updated**: 2022-06-
|
|
3
|
+
- **Last updated**: 2022-06-11T14:24:35Z
|
|
4
4
|
- **Generator**: [thi.ng/monopub](https://thi.ng/monopub)
|
|
5
5
|
|
|
6
6
|
All notable changes to this project will be documented in this file.
|
|
@@ -9,6 +9,17 @@ See [Conventional Commits](https://conventionalcommits.org/) for commit guidelin
|
|
|
9
9
|
**Note:** Unlisted _patch_ versions only involve non-code or otherwise excluded changes
|
|
10
10
|
and/or version bumps of transitive dependencies.
|
|
11
11
|
|
|
12
|
+
## [0.2.0](https://github.com/thi-ng/umbrella/tree/@thi.ng/cellular@0.2.0) (2022-06-11)
|
|
13
|
+
|
|
14
|
+
#### 🚀 Features
|
|
15
|
+
|
|
16
|
+
- add probabilities, update options ([97e6b4d](https://github.com/thi-ng/umbrella/commit/97e6b4d))
|
|
17
|
+
- add cell update probabilities
|
|
18
|
+
- add `updateProbabilistic()`
|
|
19
|
+
- extract `computeCell()`
|
|
20
|
+
- add `UpdateImageOpts1D`, update `updateImage()`
|
|
21
|
+
- replace `clearCurrent()` => `clearTarget()`
|
|
22
|
+
|
|
12
23
|
## [0.1.0](https://github.com/thi-ng/umbrella/tree/@thi.ng/cellular@0.1.0) (2022-06-09)
|
|
13
24
|
|
|
14
25
|
#### 🚀 Features
|
package/api.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import type { FnN, NumericArray } from "@thi.ng/api";
|
|
2
|
-
|
|
1
|
+
import type { Fn2, FnN, NumericArray } from "@thi.ng/api";
|
|
2
|
+
import type { IRandom } from "@thi.ng/random";
|
|
3
|
+
import type { MultiCA1D } from "./1d";
|
|
4
|
+
export declare type Target = "cells" | "mask" | "prob";
|
|
3
5
|
export declare type Kernel = NumericArray[];
|
|
4
6
|
export interface CAConfig1D {
|
|
5
7
|
/**
|
|
@@ -7,7 +9,10 @@ export interface CAConfig1D {
|
|
|
7
9
|
*/
|
|
8
10
|
kernel: Kernel;
|
|
9
11
|
/**
|
|
10
|
-
*
|
|
12
|
+
* Weight factors for each kernel offset. If {@link CASpec1D.positional} is
|
|
13
|
+
* true, these weights will all be `1 << i` where `i` is the index of each
|
|
14
|
+
* kernel offset vector. If `positional` is false, all weights will be set
|
|
15
|
+
* to 1.
|
|
11
16
|
*/
|
|
12
17
|
weights: bigint[];
|
|
13
18
|
/**
|
|
@@ -66,4 +71,47 @@ export interface CASpec1D {
|
|
|
66
71
|
*/
|
|
67
72
|
reset?: boolean;
|
|
68
73
|
}
|
|
74
|
+
export interface UpdateBufferOpts {
|
|
75
|
+
/**
|
|
76
|
+
* Per-generation perturbance probability. Default: 0%
|
|
77
|
+
*/
|
|
78
|
+
perturb: number;
|
|
79
|
+
/**
|
|
80
|
+
* Per-cell perturbance probability. Default: 5% (only used if `perturb >
|
|
81
|
+
* 0`)
|
|
82
|
+
*/
|
|
83
|
+
density: number;
|
|
84
|
+
}
|
|
85
|
+
export interface UpdateImageOpts1D {
|
|
86
|
+
/**
|
|
87
|
+
* Per-generation perturbance options for cell states array
|
|
88
|
+
*/
|
|
89
|
+
cells: Partial<UpdateBufferOpts>;
|
|
90
|
+
/**
|
|
91
|
+
* Per-generation perturbance options for cell mask array
|
|
92
|
+
*/
|
|
93
|
+
mask: Partial<UpdateBufferOpts>;
|
|
94
|
+
/**
|
|
95
|
+
* Per-generation perturbance options for cell update probability array.
|
|
96
|
+
* Only used if {@link UpdateImageOpts1D.probabilistic} is true.
|
|
97
|
+
*/
|
|
98
|
+
prob: Partial<UpdateBufferOpts>;
|
|
99
|
+
/**
|
|
100
|
+
* If true, each new generation will be updated via
|
|
101
|
+
* {@link MultiCA1D.updateProbabilistic} instead of
|
|
102
|
+
* {@link MultiCA1D.update}.
|
|
103
|
+
*/
|
|
104
|
+
probabilistic: boolean;
|
|
105
|
+
/**
|
|
106
|
+
* PRNG instance to use for perturbance. Default:
|
|
107
|
+
* {@link @thi.ng/random#SYSTEM} aka `Math.random`.
|
|
108
|
+
*/
|
|
109
|
+
rnd: IRandom;
|
|
110
|
+
/**
|
|
111
|
+
* User handler function called immediatedly after each update (computation
|
|
112
|
+
* of a new generation). The arguments passed are the {@link MultiCA1D}
|
|
113
|
+
* instance and pixel row index.
|
|
114
|
+
*/
|
|
115
|
+
onupdate: Fn2<MultiCA1D, number, void>;
|
|
116
|
+
}
|
|
69
117
|
//# sourceMappingURL=api.d.ts.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@thi.ng/cellular",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
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",
|
|
@@ -35,10 +35,10 @@
|
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
37
|
"@thi.ng/api": "^8.3.7",
|
|
38
|
-
"@thi.ng/checks": "^3.2.
|
|
38
|
+
"@thi.ng/checks": "^3.2.1",
|
|
39
39
|
"@thi.ng/errors": "^2.1.7",
|
|
40
|
-
"@thi.ng/random": "^3.3.
|
|
41
|
-
"@thi.ng/transducers": "^8.3.
|
|
40
|
+
"@thi.ng/random": "^3.3.2",
|
|
41
|
+
"@thi.ng/transducers": "^8.3.5"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"@microsoft/api-extractor": "^7.25.0",
|
|
@@ -92,5 +92,5 @@
|
|
|
92
92
|
],
|
|
93
93
|
"year": 2022
|
|
94
94
|
},
|
|
95
|
-
"gitHead": "
|
|
95
|
+
"gitHead": "ab0188234419f2d9f471de80871df930e5555bd6\n"
|
|
96
96
|
}
|