@thi.ng/cellular 0.1.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 ADDED
@@ -0,0 +1,196 @@
1
+ import type { IClear, UIntArray } from "@thi.ng/api";
2
+ import type { IRandom } from "@thi.ng/random";
3
+ import type { CAConfig1D, CASpec1D, Kernel, Target } from "./api.js";
4
+ /**
5
+ * Standard Wolfram automata 3-neighborhood (no history)
6
+ */
7
+ export declare const WOLFRAM3: Kernel;
8
+ /**
9
+ * Standard 5-neighborhood (no history)
10
+ */
11
+ export declare const WOLFRAM5: Kernel;
12
+ /**
13
+ * Standard 7-neighborhood (no history)
14
+ */
15
+ export declare const WOLFRAM7: Kernel;
16
+ /**
17
+ * Implementation of a 1D cellular automata environment with support for
18
+ * multiple automata, each with its own settings for replication rules,
19
+ * arbitrary neighborhood kernels (optionally with short term memory) and number
20
+ * of cell states, all selectable via a shared per-cell mask array. This generic
21
+ * setup enables many novel and unusual CA setups as well as coevolution of
22
+ * multiple CAs within a shared environment.
23
+ *
24
+ * @remarks
25
+ * ### Neighborhoods
26
+ *
27
+ * Cell neighborhoods are defined via an arbitrary number of 2D offset vectors
28
+ * `[x, y]`, where `x` coordinates are horizontal offsets and positive `y`
29
+ * coordinates are used to refer to previous generations (e.g. 0 = current gen,
30
+ * 1 = T-1, 2 = T-2 etc.) and thereby providing a form of short term memory for
31
+ * that specific automata. Negative `y` coords will lead to cells being ignored.
32
+ *
33
+ * ### Rule encoding
34
+ *
35
+ * Automata rules are encoded as JS `BigInt` values and are considered
36
+ * anisotropic by default. If isotropy is desired, it has to be explicitly
37
+ * pre-encoded [out of scope of this library]. There's also built-in optional
38
+ * support for position independent neighborhood encoding, only considering the
39
+ * number/count of non-zero cells. An encoded rule ID and its overall magnitude
40
+ * is directly related and dependent on the size and shape of its kernel config,
41
+ * e.g.:
42
+ *
43
+ * ```ts
44
+ * kernel = [[-2, 1], [-1, 0], [0, 0], [1, 0], [2, 1]]
45
+ * ```
46
+ *
47
+ * This example kernel defines a 5-cell neighborhood with a max. short term
48
+ * memory of one additional previous generation (i.e. the [-2,1] and [2,1]
49
+ * offsets)
50
+ *
51
+ * The rules related to this kernel have a 32 bit address space (4 billion
52
+ * possibilities), due to 2^5 = 32 and each kernel offset being assigned a
53
+ * distinct bit value by default, i.e. first kernel offset = 2^0, second kernel
54
+ * offset = 2^1, third = 2^2, fourth = 2^3, fifth = 2^4. Via the
55
+ * {@link CASpec1D.positional} config option, this behavior can be overridden
56
+ * per kernel, to achieve position-independent kernels (with much smaller rule
57
+ * spaces).
58
+ *
59
+ * Given the following example cell matrix with the center cell highlighted with
60
+ * caret (`^`):
61
+ *
62
+ * ```text
63
+ * T-1: 2 0 1 2 1
64
+ * T-0: 0 1 0 3 0
65
+ * ^
66
+ * ```
67
+ *
68
+ * The above example kernel will select the following values and assign bit
69
+ * positions (for all non-zero cell states) to compute a summed ID:
70
+ *
71
+ * | k index | offset | cell value | encoded |
72
+ * |--------:|-----------|-----------:|--------:|
73
+ * | 0 | `[-2, 1]` | 2 | 1 |
74
+ * | 1 | `[-1, 0]` | 1 | 2 |
75
+ * | 2 | `[0, 0]` | 0 | 0 |
76
+ * | 3 | `[1, 0]` | 3 | 8 |
77
+ * | 4 | `[2, 1]` | 1 | 16 |
78
+ *
79
+ * Final encoded neighborhood sum: 1 + 2 + 8 + 16 = 27
80
+ *
81
+ * To determine if a the current cell should be active or not in the next
82
+ * generation, we now use that encoded sum as bit position to test a single bit
83
+ * of the automata's rule ID, i.e. here we're testing bit 27. If that
84
+ * corresponding bit is set in the rule ID, the cell's state will be increased
85
+ * by 1.
86
+ *
87
+ * ### Cell states
88
+ *
89
+ * Each automata config can define a max. number of possible cell states (aka
90
+ * age). Once a cell reaches the configured `numStates`, it automatically resets
91
+ * to zero. This is by default, but can be overridden via the
92
+ * {@link CASpec1D.reset} option. Conversely, if the corresponding bit is _not_
93
+ * set in the rule ID, the cell state will be zeroed too.
94
+ *
95
+ * ### Wraparound
96
+ *
97
+ * By default the environment is configured to be toroidal, i.e. both left/right
98
+ * sides of the env are connected. The behavior can be controlled via a ctor arg
99
+ * and/or at runtime via the {@link MultiCA1D.wrap} property.
100
+ *
101
+ * ### Masks
102
+ *
103
+ * The {@link MultiCA1D.mask} array can be used to select different CA
104
+ * configurations for each cell in the environment. Because this mask array is
105
+ * initialized to zero, only the first CA configuration will be used for all
106
+ * cells in the environment by default. It's the user's responsibility to manage
107
+ * the mask and select/enable other (if any) CA configs for individual cells
108
+ * (usually cell ranges). The values stored in this array correspond to the
109
+ * indices of the {@link MultiCA1D.config} array given at construction.
110
+ *
111
+ * ### Limits
112
+ *
113
+ * Due to using `Uint8Arrays` for storage, only up to 256 cell states are
114
+ * supported. The same limit applies to the number of CA configs given.
115
+ *
116
+ * @example
117
+ * ```ts
118
+ * // classic Wolfram Rule 110 automata
119
+ * const wolfram = new MultiCA1D(
120
+ * [{
121
+ * kernel: [[-1, 0], [0, 0], [1, 0]],
122
+ * rule: 110,
123
+ * states: 2,
124
+ * reset: false
125
+ * }],
126
+ * 256
127
+ * )
128
+ * ```
129
+ */
130
+ export declare class MultiCA1D implements IClear {
131
+ width: number;
132
+ wrap: boolean;
133
+ configs: CAConfig1D[];
134
+ rows: number;
135
+ numStates: number;
136
+ mask: Uint8Array;
137
+ gens: Uint8Array[];
138
+ constructor(configs: CASpec1D[], width: number, wrap?: boolean);
139
+ get current(): Uint8Array;
140
+ get previous(): Uint8Array;
141
+ clear(): void;
142
+ clearCurrent(): void;
143
+ resize(width: number): void;
144
+ /**
145
+ * Sets a parametric pattern in the current generation or mask array.
146
+ *
147
+ * @param target - target buffer ID to apply pattern
148
+ * @param width - number of consecutive cells per segment
149
+ * @param stride - number of cells between each pattern segment
150
+ * @param val - start cell value per segment
151
+ * @param inc - cell value increment
152
+ * @param offset - start cell offset
153
+ */
154
+ setPattern(target: Target, width: number, stride: number, val?: number, inc?: number, offset?: number): this;
155
+ /**
156
+ * Sets cells in current generation array to a random state using given
157
+ * `probability` and optional PRNG ({@link @thi.ng/random#IRandom} instance).
158
+ *
159
+ * @param target
160
+ * @param prob
161
+ * @param rnd
162
+ */
163
+ setNoise(target: Target, prob?: number, rnd?: IRandom): this;
164
+ /**
165
+ * Computes a single new generation using current cell states and mask. See
166
+ * {@link MultiCA1D.updateImage} for batch updates.
167
+ */
168
+ update(): void;
169
+ /**
170
+ * Batch version of {@link MultiCA1D.update} to compute an entire image of
171
+ * given `height` (and same width as this CA instance has been configured
172
+ * to). Fill given `pixels` array with consecutive generations. For each
173
+ * iteration there's `perturb` probability (default: 0%) to call
174
+ * {@link MultiCA1D.setNoise} with given `density` (default: 5%) and using
175
+ * optionally provided PRNG. This can be helpful to sporadically introduce
176
+ * noise into the sim and break otherwise constant patterns emerging.
177
+ *
178
+ * @param pixels
179
+ * @param height
180
+ * @param perturb
181
+ * @param density
182
+ * @param rnd
183
+ */
184
+ updateImage(pixels: UIntArray, height: number, perturb?: number, density?: number, rnd?: IRandom): void;
185
+ rotate(dir: number): void;
186
+ protected _getTarget(target: Target): [Uint8Array, number];
187
+ }
188
+ /**
189
+ * Creates a random rule ID for given `kernelSize` and using optionally provided
190
+ * `rnd` {@link @thi.ng/random#IRandom} instance.
191
+ *
192
+ * @param kernelSize
193
+ * @param rnd
194
+ */
195
+ export declare const randomRule1D: (kernelSize: number, rnd?: IRandom) => bigint;
196
+ //# sourceMappingURL=1d.d.ts.map
package/1d.js ADDED
@@ -0,0 +1,312 @@
1
+ import { isBigInt } from "@thi.ng/checks/is-bigint";
2
+ import { assert } from "@thi.ng/errors/assert";
3
+ import { SYSTEM } from "@thi.ng/random/system";
4
+ import { repeat } from "@thi.ng/transducers";
5
+ import { map } from "@thi.ng/transducers/map";
6
+ import { mapcat } from "@thi.ng/transducers/mapcat";
7
+ import { max } from "@thi.ng/transducers/max";
8
+ import { pluck } from "@thi.ng/transducers/pluck";
9
+ import { repeatedly } from "@thi.ng/transducers/repeatedly";
10
+ import { transduce } from "@thi.ng/transducers/transduce";
11
+ const $0 = BigInt(0);
12
+ const $1 = BigInt(1);
13
+ const $32 = BigInt(32);
14
+ /**
15
+ * Standard Wolfram automata 3-neighborhood (no history)
16
+ */
17
+ export const WOLFRAM3 = [
18
+ [-1, 0],
19
+ [0, 0],
20
+ [1, 0],
21
+ ];
22
+ /**
23
+ * Standard 5-neighborhood (no history)
24
+ */
25
+ export const WOLFRAM5 = [[-2, 0], ...WOLFRAM3, [2, 0]];
26
+ /**
27
+ * Standard 7-neighborhood (no history)
28
+ */
29
+ export const WOLFRAM7 = [[-3, 0], ...WOLFRAM5, [3, 0]];
30
+ /**
31
+ * Implementation of a 1D cellular automata environment with support for
32
+ * multiple automata, each with its own settings for replication rules,
33
+ * arbitrary neighborhood kernels (optionally with short term memory) and number
34
+ * of cell states, all selectable via a shared per-cell mask array. This generic
35
+ * setup enables many novel and unusual CA setups as well as coevolution of
36
+ * multiple CAs within a shared environment.
37
+ *
38
+ * @remarks
39
+ * ### Neighborhoods
40
+ *
41
+ * Cell neighborhoods are defined via an arbitrary number of 2D offset vectors
42
+ * `[x, y]`, where `x` coordinates are horizontal offsets and positive `y`
43
+ * coordinates are used to refer to previous generations (e.g. 0 = current gen,
44
+ * 1 = T-1, 2 = T-2 etc.) and thereby providing a form of short term memory for
45
+ * that specific automata. Negative `y` coords will lead to cells being ignored.
46
+ *
47
+ * ### Rule encoding
48
+ *
49
+ * Automata rules are encoded as JS `BigInt` values and are considered
50
+ * anisotropic by default. If isotropy is desired, it has to be explicitly
51
+ * pre-encoded [out of scope of this library]. There's also built-in optional
52
+ * support for position independent neighborhood encoding, only considering the
53
+ * number/count of non-zero cells. An encoded rule ID and its overall magnitude
54
+ * is directly related and dependent on the size and shape of its kernel config,
55
+ * e.g.:
56
+ *
57
+ * ```ts
58
+ * kernel = [[-2, 1], [-1, 0], [0, 0], [1, 0], [2, 1]]
59
+ * ```
60
+ *
61
+ * This example kernel defines a 5-cell neighborhood with a max. short term
62
+ * memory of one additional previous generation (i.e. the [-2,1] and [2,1]
63
+ * offsets)
64
+ *
65
+ * The rules related to this kernel have a 32 bit address space (4 billion
66
+ * possibilities), due to 2^5 = 32 and each kernel offset being assigned a
67
+ * distinct bit value by default, i.e. first kernel offset = 2^0, second kernel
68
+ * offset = 2^1, third = 2^2, fourth = 2^3, fifth = 2^4. Via the
69
+ * {@link CASpec1D.positional} config option, this behavior can be overridden
70
+ * per kernel, to achieve position-independent kernels (with much smaller rule
71
+ * spaces).
72
+ *
73
+ * Given the following example cell matrix with the center cell highlighted with
74
+ * caret (`^`):
75
+ *
76
+ * ```text
77
+ * T-1: 2 0 1 2 1
78
+ * T-0: 0 1 0 3 0
79
+ * ^
80
+ * ```
81
+ *
82
+ * The above example kernel will select the following values and assign bit
83
+ * positions (for all non-zero cell states) to compute a summed ID:
84
+ *
85
+ * | k index | offset | cell value | encoded |
86
+ * |--------:|-----------|-----------:|--------:|
87
+ * | 0 | `[-2, 1]` | 2 | 1 |
88
+ * | 1 | `[-1, 0]` | 1 | 2 |
89
+ * | 2 | `[0, 0]` | 0 | 0 |
90
+ * | 3 | `[1, 0]` | 3 | 8 |
91
+ * | 4 | `[2, 1]` | 1 | 16 |
92
+ *
93
+ * Final encoded neighborhood sum: 1 + 2 + 8 + 16 = 27
94
+ *
95
+ * To determine if a the current cell should be active or not in the next
96
+ * generation, we now use that encoded sum as bit position to test a single bit
97
+ * of the automata's rule ID, i.e. here we're testing bit 27. If that
98
+ * corresponding bit is set in the rule ID, the cell's state will be increased
99
+ * by 1.
100
+ *
101
+ * ### Cell states
102
+ *
103
+ * Each automata config can define a max. number of possible cell states (aka
104
+ * age). Once a cell reaches the configured `numStates`, it automatically resets
105
+ * to zero. This is by default, but can be overridden via the
106
+ * {@link CASpec1D.reset} option. Conversely, if the corresponding bit is _not_
107
+ * set in the rule ID, the cell state will be zeroed too.
108
+ *
109
+ * ### Wraparound
110
+ *
111
+ * By default the environment is configured to be toroidal, i.e. both left/right
112
+ * sides of the env are connected. The behavior can be controlled via a ctor arg
113
+ * and/or at runtime via the {@link MultiCA1D.wrap} property.
114
+ *
115
+ * ### Masks
116
+ *
117
+ * The {@link MultiCA1D.mask} array can be used to select different CA
118
+ * configurations for each cell in the environment. Because this mask array is
119
+ * initialized to zero, only the first CA configuration will be used for all
120
+ * cells in the environment by default. It's the user's responsibility to manage
121
+ * the mask and select/enable other (if any) CA configs for individual cells
122
+ * (usually cell ranges). The values stored in this array correspond to the
123
+ * indices of the {@link MultiCA1D.config} array given at construction.
124
+ *
125
+ * ### Limits
126
+ *
127
+ * Due to using `Uint8Arrays` for storage, only up to 256 cell states are
128
+ * supported. The same limit applies to the number of CA configs given.
129
+ *
130
+ * @example
131
+ * ```ts
132
+ * // classic Wolfram Rule 110 automata
133
+ * const wolfram = new MultiCA1D(
134
+ * [{
135
+ * kernel: [[-1, 0], [0, 0], [1, 0]],
136
+ * rule: 110,
137
+ * states: 2,
138
+ * reset: false
139
+ * }],
140
+ * 256
141
+ * )
142
+ * ```
143
+ */
144
+ export class MultiCA1D {
145
+ constructor(configs, width, wrap = true) {
146
+ this.width = width;
147
+ this.wrap = wrap;
148
+ this.configs = configs.map(__compileSpec);
149
+ this.rows =
150
+ transduce(mapcat((c) => map((k) => k[1], c.kernel)), max(), configs) + 1;
151
+ this.numStates = transduce(pluck("states"), max(), configs);
152
+ assert(this.numStates >= 2 && this.numStates <= 256, "num states must be in [2..256] range");
153
+ this.resize(width);
154
+ }
155
+ get current() {
156
+ return this.gens[1];
157
+ }
158
+ get previous() {
159
+ return this.gens[2 % this.gens.length];
160
+ }
161
+ clear() {
162
+ this.gens.forEach((g) => g.fill(0));
163
+ }
164
+ clearCurrent() {
165
+ this.current.fill(0);
166
+ }
167
+ resize(width) {
168
+ this.width = width;
169
+ this.mask = new Uint8Array(width);
170
+ this.gens = [...repeatedly(() => new Uint8Array(width), this.rows + 1)];
171
+ }
172
+ /**
173
+ * Sets a parametric pattern in the current generation or mask array.
174
+ *
175
+ * @param target - target buffer ID to apply pattern
176
+ * @param width - number of consecutive cells per segment
177
+ * @param stride - number of cells between each pattern segment
178
+ * @param val - start cell value per segment
179
+ * @param inc - cell value increment
180
+ * @param offset - start cell offset
181
+ */
182
+ setPattern(target, width, stride, val = 1, inc = 0, offset = 0) {
183
+ const [dest, num] = this._getTarget(target);
184
+ for (let x = offset, w = this.width; x < w; x += stride) {
185
+ for (let k = 0, v = val; k < width; k++, v += inc) {
186
+ dest[x + k] = v % num;
187
+ }
188
+ }
189
+ return this;
190
+ }
191
+ /**
192
+ * Sets cells in current generation array to a random state using given
193
+ * `probability` and optional PRNG ({@link @thi.ng/random#IRandom} instance).
194
+ *
195
+ * @param target
196
+ * @param prob
197
+ * @param rnd
198
+ */
199
+ setNoise(target, prob = 0.5, rnd = SYSTEM) {
200
+ const [dest, num] = this._getTarget(target);
201
+ for (let x = 0, width = this.width; x < width; x++) {
202
+ if (rnd.float() < prob)
203
+ dest[x] = rnd.int() % num;
204
+ }
205
+ return this;
206
+ }
207
+ /**
208
+ * Computes a single new generation using current cell states and mask. See
209
+ * {@link MultiCA1D.updateImage} for batch updates.
210
+ */
211
+ update() {
212
+ const { width, gens, configs, mask, wrap } = this;
213
+ const [next, curr] = gens;
214
+ for (let x = 0; x < width; x++) {
215
+ const { rule, kernel, weights, fn } = configs[mask[x]];
216
+ let sum = $0;
217
+ for (let i = 0, n = kernel.length; i < n; i++) {
218
+ const k = kernel[i];
219
+ let xx = x + k[0];
220
+ if (wrap) {
221
+ if (xx < 0)
222
+ xx += width;
223
+ else if (xx >= width)
224
+ xx -= width;
225
+ }
226
+ else if (xx < 0 || xx >= width)
227
+ continue;
228
+ const y = k[1];
229
+ if (y >= 0 && gens[1 + y][xx] !== 0)
230
+ sum += weights[i];
231
+ }
232
+ next[x] = rule & ($1 << sum) ? fn(curr[x]) : 0;
233
+ }
234
+ gens.unshift(gens.pop());
235
+ }
236
+ /**
237
+ * Batch version of {@link MultiCA1D.update} to compute an entire image of
238
+ * given `height` (and same width as this CA instance has been configured
239
+ * to). Fill given `pixels` array with consecutive generations. For each
240
+ * iteration there's `perturb` probability (default: 0%) to call
241
+ * {@link MultiCA1D.setNoise} with given `density` (default: 5%) and using
242
+ * optionally provided PRNG. This can be helpful to sporadically introduce
243
+ * noise into the sim and break otherwise constant patterns emerging.
244
+ *
245
+ * @param pixels
246
+ * @param height
247
+ * @param perturb
248
+ * @param density
249
+ * @param rnd
250
+ */
251
+ updateImage(pixels, height, perturb = 0, density = 0.05, rnd = SYSTEM) {
252
+ for (let y = 0; y < height; y++) {
253
+ rnd.float() < perturb && this.setNoise("cells", density, rnd);
254
+ this.update();
255
+ pixels.set(this.current, y * this.width);
256
+ }
257
+ }
258
+ rotate(dir) {
259
+ __rotate(this.current, dir);
260
+ __rotate(this.mask, dir);
261
+ }
262
+ _getTarget(target) {
263
+ return target === "cells"
264
+ ? [this.current, this.numStates]
265
+ : [this.mask, this.configs.length];
266
+ }
267
+ }
268
+ const __compileSpec = ({ rule, kernel, positional, states, reset, }) => {
269
+ const max = states - 1;
270
+ return {
271
+ kernel,
272
+ states,
273
+ rule: isBigInt(rule) ? rule : BigInt(rule),
274
+ weights: positional !== false
275
+ ? kernel.map((_, i) => BigInt(2) ** BigInt(i))
276
+ : [...repeat($1, kernel.length)],
277
+ fn: reset !== false
278
+ ? (y) => (++y >= states ? 0 : y)
279
+ : (y) => (++y >= max ? max : y),
280
+ };
281
+ };
282
+ const __rotate = (buf, dir) => {
283
+ if (dir < 0) {
284
+ const tmp = buf.slice(0, -dir);
285
+ buf.copyWithin(0, -dir);
286
+ buf.set(tmp, buf.length + dir);
287
+ }
288
+ else if (dir > 0) {
289
+ const tmp = buf.slice(buf.length - dir);
290
+ buf.copyWithin(dir, 0);
291
+ buf.set(tmp, 0);
292
+ }
293
+ };
294
+ /**
295
+ * Creates a random rule ID for given `kernelSize` and using optionally provided
296
+ * `rnd` {@link @thi.ng/random#IRandom} instance.
297
+ *
298
+ * @param kernelSize
299
+ * @param rnd
300
+ */
301
+ export const randomRule1D = (kernelSize, rnd = SYSTEM) => {
302
+ const n = BigInt(2 ** kernelSize);
303
+ let id = $0;
304
+ for (let i = $0; i < n; i += $32) {
305
+ id <<= $32;
306
+ let mask = n - i;
307
+ if (mask > $32)
308
+ mask = $32;
309
+ id |= BigInt(rnd.int()) & (($1 << mask) - $1);
310
+ }
311
+ return id;
312
+ };
package/CHANGELOG.md ADDED
@@ -0,0 +1,19 @@
1
+ # Change Log
2
+
3
+ - **Last updated**: 2022-06-09T16:14:01Z
4
+ - **Generator**: [thi.ng/monopub](https://thi.ng/monopub)
5
+
6
+ All notable changes to this project will be documented in this file.
7
+ See [Conventional Commits](https://conventionalcommits.org/) for commit guidelines.
8
+
9
+ **Note:** Unlisted _patch_ versions only involve non-code or otherwise excluded changes
10
+ and/or version bumps of transitive dependencies.
11
+
12
+ ## [0.1.0](https://github.com/thi-ng/umbrella/tree/@thi.ng/cellular@0.1.0) (2022-06-09)
13
+
14
+ #### 🚀 Features
15
+
16
+ - add kernel presets, simplify CASpec1D ([3ee4a25](https://github.com/thi-ng/umbrella/commit/3ee4a25))
17
+ - update setPattern/setNoise() ([2ef2013](https://github.com/thi-ng/umbrella/commit/2ef2013))
18
+ - add support to operate on diff target buffers (cells/mask)
19
+ - import as new pkg ([aaec2ed](https://github.com/thi-ng/umbrella/commit/aaec2ed))
package/LICENSE ADDED
@@ -0,0 +1,201 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+ 1. Definitions.
8
+
9
+ "License" shall mean the terms and conditions for use, reproduction,
10
+ and distribution as defined by Sections 1 through 9 of this document.
11
+
12
+ "Licensor" shall mean the copyright owner or entity authorized by
13
+ the copyright owner that is granting the License.
14
+
15
+ "Legal Entity" shall mean the union of the acting entity and all
16
+ other entities that control, are controlled by, or are under common
17
+ control with that entity. For the purposes of this definition,
18
+ "control" means (i) the power, direct or indirect, to cause the
19
+ direction or management of such entity, whether by contract or
20
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
21
+ outstanding shares, or (iii) beneficial ownership of such entity.
22
+
23
+ "You" (or "Your") shall mean an individual or Legal Entity
24
+ exercising permissions granted by this License.
25
+
26
+ "Source" form shall mean the preferred form for making modifications,
27
+ including but not limited to software source code, documentation
28
+ source, and configuration files.
29
+
30
+ "Object" form shall mean any form resulting from mechanical
31
+ transformation or translation of a Source form, including but
32
+ not limited to compiled object code, generated documentation,
33
+ and conversions to other media types.
34
+
35
+ "Work" shall mean the work of authorship, whether in Source or
36
+ Object form, made available under the License, as indicated by a
37
+ copyright notice that is included in or attached to the work
38
+ (an example is provided in the Appendix below).
39
+
40
+ "Derivative Works" shall mean any work, whether in Source or Object
41
+ form, that is based on (or derived from) the Work and for which the
42
+ editorial revisions, annotations, elaborations, or other modifications
43
+ represent, as a whole, an original work of authorship. For the purposes
44
+ of this License, Derivative Works shall not include works that remain
45
+ separable from, or merely link (or bind by name) to the interfaces of,
46
+ the Work and Derivative Works thereof.
47
+
48
+ "Contribution" shall mean any work of authorship, including
49
+ the original version of the Work and any modifications or additions
50
+ to that Work or Derivative Works thereof, that is intentionally
51
+ submitted to Licensor for inclusion in the Work by the copyright owner
52
+ or by an individual or Legal Entity authorized to submit on behalf of
53
+ the copyright owner. For the purposes of this definition, "submitted"
54
+ means any form of electronic, verbal, or written communication sent
55
+ to the Licensor or its representatives, including but not limited to
56
+ communication on electronic mailing lists, source code control systems,
57
+ and issue tracking systems that are managed by, or on behalf of, the
58
+ Licensor for the purpose of discussing and improving the Work, but
59
+ excluding communication that is conspicuously marked or otherwise
60
+ designated in writing by the copyright owner as "Not a Contribution."
61
+
62
+ "Contributor" shall mean Licensor and any individual or Legal Entity
63
+ on behalf of whom a Contribution has been received by Licensor and
64
+ subsequently incorporated within the Work.
65
+
66
+ 2. Grant of Copyright License. Subject to the terms and conditions of
67
+ this License, each Contributor hereby grants to You a perpetual,
68
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69
+ copyright license to reproduce, prepare Derivative Works of,
70
+ publicly display, publicly perform, sublicense, and distribute the
71
+ Work and such Derivative Works in Source or Object form.
72
+
73
+ 3. Grant of Patent License. Subject to the terms and conditions of
74
+ this License, each Contributor hereby grants to You a perpetual,
75
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76
+ (except as stated in this section) patent license to make, have made,
77
+ use, offer to sell, sell, import, and otherwise transfer the Work,
78
+ where such license applies only to those patent claims licensable
79
+ by such Contributor that are necessarily infringed by their
80
+ Contribution(s) alone or by combination of their Contribution(s)
81
+ with the Work to which such Contribution(s) was submitted. If You
82
+ institute patent litigation against any entity (including a
83
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
84
+ or a Contribution incorporated within the Work constitutes direct
85
+ or contributory patent infringement, then any patent licenses
86
+ granted to You under this License for that Work shall terminate
87
+ as of the date such litigation is filed.
88
+
89
+ 4. Redistribution. You may reproduce and distribute copies of the
90
+ Work or Derivative Works thereof in any medium, with or without
91
+ modifications, and in Source or Object form, provided that You
92
+ meet the following conditions:
93
+
94
+ (a) You must give any other recipients of the Work or
95
+ Derivative Works a copy of this License; and
96
+
97
+ (b) You must cause any modified files to carry prominent notices
98
+ stating that You changed the files; and
99
+
100
+ (c) You must retain, in the Source form of any Derivative Works
101
+ that You distribute, all copyright, patent, trademark, and
102
+ attribution notices from the Source form of the Work,
103
+ excluding those notices that do not pertain to any part of
104
+ the Derivative Works; and
105
+
106
+ (d) If the Work includes a "NOTICE" text file as part of its
107
+ distribution, then any Derivative Works that You distribute must
108
+ include a readable copy of the attribution notices contained
109
+ within such NOTICE file, excluding those notices that do not
110
+ pertain to any part of the Derivative Works, in at least one
111
+ of the following places: within a NOTICE text file distributed
112
+ as part of the Derivative Works; within the Source form or
113
+ documentation, if provided along with the Derivative Works; or,
114
+ within a display generated by the Derivative Works, if and
115
+ wherever such third-party notices normally appear. The contents
116
+ of the NOTICE file are for informational purposes only and
117
+ do not modify the License. You may add Your own attribution
118
+ notices within Derivative Works that You distribute, alongside
119
+ or as an addendum to the NOTICE text from the Work, provided
120
+ that such additional attribution notices cannot be construed
121
+ as modifying the License.
122
+
123
+ You may add Your own copyright statement to Your modifications and
124
+ may provide additional or different license terms and conditions
125
+ for use, reproduction, or distribution of Your modifications, or
126
+ for any such Derivative Works as a whole, provided Your use,
127
+ reproduction, and distribution of the Work otherwise complies with
128
+ the conditions stated in this License.
129
+
130
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
131
+ any Contribution intentionally submitted for inclusion in the Work
132
+ by You to the Licensor shall be under the terms and conditions of
133
+ this License, without any additional terms or conditions.
134
+ Notwithstanding the above, nothing herein shall supersede or modify
135
+ the terms of any separate license agreement you may have executed
136
+ with Licensor regarding such Contributions.
137
+
138
+ 6. Trademarks. This License does not grant permission to use the trade
139
+ names, trademarks, service marks, or product names of the Licensor,
140
+ except as required for reasonable and customary use in describing the
141
+ origin of the Work and reproducing the content of the NOTICE file.
142
+
143
+ 7. Disclaimer of Warranty. Unless required by applicable law or
144
+ agreed to in writing, Licensor provides the Work (and each
145
+ Contributor provides its Contributions) on an "AS IS" BASIS,
146
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147
+ implied, including, without limitation, any warranties or conditions
148
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149
+ PARTICULAR PURPOSE. You are solely responsible for determining the
150
+ appropriateness of using or redistributing the Work and assume any
151
+ risks associated with Your exercise of permissions under this License.
152
+
153
+ 8. Limitation of Liability. In no event and under no legal theory,
154
+ whether in tort (including negligence), contract, or otherwise,
155
+ unless required by applicable law (such as deliberate and grossly
156
+ negligent acts) or agreed to in writing, shall any Contributor be
157
+ liable to You for damages, including any direct, indirect, special,
158
+ incidental, or consequential damages of any character arising as a
159
+ result of this License or out of the use or inability to use the
160
+ Work (including but not limited to damages for loss of goodwill,
161
+ work stoppage, computer failure or malfunction, or any and all
162
+ other commercial damages or losses), even if such Contributor
163
+ has been advised of the possibility of such damages.
164
+
165
+ 9. Accepting Warranty or Additional Liability. While redistributing
166
+ the Work or Derivative Works thereof, You may choose to offer,
167
+ and charge a fee for, acceptance of support, warranty, indemnity,
168
+ or other liability obligations and/or rights consistent with this
169
+ License. However, in accepting such obligations, You may act only
170
+ on Your own behalf and on Your sole responsibility, not on behalf
171
+ of any other Contributor, and only if You agree to indemnify,
172
+ defend, and hold each Contributor harmless for any liability
173
+ incurred by, or claims asserted against, such Contributor by reason
174
+ of your accepting any such warranty or additional liability.
175
+
176
+ END OF TERMS AND CONDITIONS
177
+
178
+ APPENDIX: How to apply the Apache License to your work.
179
+
180
+ To apply the Apache License to your work, attach the following
181
+ boilerplate notice, with the fields enclosed by brackets "{}"
182
+ replaced with your own identifying information. (Don't include
183
+ the brackets!) The text should be enclosed in the appropriate
184
+ comment syntax for the file format. We also recommend that a
185
+ file or class name and description of purpose be included on the
186
+ same "printed page" as the copyright notice for easier
187
+ identification within third-party archives.
188
+
189
+ Copyright {yyyy} {name of copyright owner}
190
+
191
+ Licensed under the Apache License, Version 2.0 (the "License");
192
+ you may not use this file except in compliance with the License.
193
+ You may obtain a copy of the License at
194
+
195
+ http://www.apache.org/licenses/LICENSE-2.0
196
+
197
+ Unless required by applicable law or agreed to in writing, software
198
+ distributed under the License is distributed on an "AS IS" BASIS,
199
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200
+ See the License for the specific language governing permissions and
201
+ limitations under the License.
package/README.md ADDED
@@ -0,0 +1,310 @@
1
+ <!-- This file is generated - DO NOT EDIT! -->
2
+
3
+ # ![cellular](https://media.thi.ng/umbrella/banners/thing-cellular.svg?1a3e0e44)
4
+
5
+ [![npm version](https://img.shields.io/npm/v/@thi.ng/cellular.svg)](https://www.npmjs.com/package/@thi.ng/cellular)
6
+ ![npm downloads](https://img.shields.io/npm/dm/@thi.ng/cellular.svg)
7
+ [![Twitter Follow](https://img.shields.io/twitter/follow/thing_umbrella.svg?style=flat-square&label=twitter)](https://twitter.com/thing_umbrella)
8
+
9
+ This project is part of the
10
+ [@thi.ng/umbrella](https://github.com/thi-ng/umbrella/) monorepo.
11
+
12
+ - [About](#about)
13
+ - [Neighborhoods](#neighborhoods)
14
+ - [Rule encoding](#rule-encoding)
15
+ - [Cell states](#cell-states)
16
+ - [Wraparound](#wraparound)
17
+ - [Masks](#masks)
18
+ - [Limits](#limits)
19
+ - [Status](#status)
20
+ - [Related packages](#related-packages)
21
+ - [Installation](#installation)
22
+ - [Dependencies](#dependencies)
23
+ - [API](#api)
24
+ - [Code examples](#code-examples)
25
+ - [Classic Wolfram](#classic-wolfram)
26
+ - [Custom kernels & multiple rules](#custom-kernels--multiple-rules)
27
+ - [Authors](#authors)
28
+ - [License](#license)
29
+
30
+ ## About
31
+
32
+ ![Custom cellular automata w/ 7-neighborhood & 128 states](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/cellular/hero.png)
33
+
34
+ Highly customizable 1D cellular automata, shared env, multiple rules, arbitrary sized/shaped neighborhoods, short term memory, cell states etc..
35
+
36
+ The generic implementation provided by this package enables many novel and
37
+ unusual CA setups as well as coevolution of multiple CAs within a shared
38
+ environment.
39
+
40
+ This library also forms the core of **C-SCAPE**, a generative art project by the
41
+ author. Visit the [project site](https://www.fxhash.xyz/generative/slug/c-scape)
42
+ to get a better impression and overview of the multitude of possible results
43
+ (still nothing more than a small glimpse only)...
44
+
45
+ ### Neighborhoods
46
+
47
+ Cell neighborhoods are defined via an arbitrary number of 2D offset vectors `[x,
48
+ y]`, where `x` coordinates are horizontal offsets and positive `y` coordinates
49
+ are used to refer to previous generations (e.g. 0 = current gen, 1 = T-1, 2 =
50
+ T-2 etc.) and thereby providing a form of short term memory for that specific
51
+ automata. Negative `y` coords will lead to cells being ignored.
52
+
53
+ ### Rule encoding
54
+
55
+ Automata rules are encoded as JS `BigInt` values and are considered anisotropic
56
+ by default. If isotropy is desired, it has to be explicitly pre-encoded (out of
57
+ scope of this library). There's also built-in optional support for position
58
+ independent neighborhood encoding, only considering the number/count of non-zero
59
+ cells. An encoded rule ID and its overall magnitude is directly related and
60
+ dependent on the size and shape of its kernel config, e.g.:
61
+
62
+ ```ts
63
+ kernel = [[-2, 1], [-1, 0], [0, 0], [1, 0], [2, 1]]
64
+ ```
65
+
66
+ This example kernel defines a 5-cell neighborhood with a max. short term memory
67
+ of one additional previous generation (i.e. the [-2,1] and [2,1] offsets)
68
+
69
+ The rules related to this kernel have a 32 bit address space (4 billion
70
+ possibilities), due to 2^5 = 32 and each kernel offset being assigned a distinct
71
+ bit value by default, i.e. first kernel offset = 2^0, second kernel offset =
72
+ 2^1, third = 2^2, fourth = 2^3, fifth = 2^4. Via the `positional` config option,
73
+ this behavior can be overridden per kernel, to achieve position-independent
74
+ kernels (with much smaller rule spaces).
75
+
76
+ Given the following example cell matrix with the center cell highlighted with
77
+ caret (`^`):
78
+
79
+ ```text
80
+ T-1: 2 0 1 2 1
81
+ T-0: 0 1 0 3 0
82
+ ^
83
+ ```
84
+
85
+ The above example kernel will select the following values and assign bit
86
+ positions (for all non-zero cell states) to compute a summed ID:
87
+
88
+ | k index | offset | cell value | encoded |
89
+ |--------:|-----------|-----------:|---------:|
90
+ | 0 | `[-2, 1]` | 2 | 2^0 = 1 |
91
+ | 1 | `[-1, 0]` | 1 | 2^1 = 2 |
92
+ | 2 | `[0, 0]` | 0 | 0 |
93
+ | 3 | `[1, 0]` | 3 | 2^3 = 8 |
94
+ | 4 | `[2, 1]` | 1 | 2^4 = 16 |
95
+
96
+ Final encoded neighborhood sum: 1 + 2 + 8 + 16 = 27
97
+
98
+ To determine if a the current cell should be active or not in the next
99
+ generation, we now use that encoded sum as bit position to test a single bit of
100
+ the automata's rule ID, i.e. here we're testing bit 27. If that corresponding
101
+ bit is set in the rule ID, the cell's state will be increased by 1.
102
+
103
+ ### Cell states
104
+
105
+ Each automata config can define a max. number of possible cell states (aka age).
106
+ Once a cell reaches the configured `numStates`, it automatically resets to zero.
107
+ This is by default, but can be overridden via the `reset` option. Conversely, if
108
+ the corresponding bit is _not_ set in the rule ID, the cell state will be zeroed
109
+ too.
110
+
111
+ ### Wraparound
112
+
113
+ By default the environment is configured to be toroidal, i.e. both left/right
114
+ sides of the env are connected. The behavior can be controlled via a ctor arg
115
+ and/or at runtime via the `wrap` property.
116
+
117
+ ### Masks
118
+
119
+ The `mask` array can be used to select different CA configurations for each cell
120
+ in the environment. Because this mask array is initialized to zero, only the
121
+ first CA configuration will be used for all cells in the environment by default.
122
+ It's the user's responsibility to manage the mask and select/enable other (if
123
+ any) CA configs for individual cells (usually cell ranges). The values stored in
124
+ this array correspond to the indices of the CA configurations given at
125
+ construction.
126
+
127
+ ### Limits
128
+
129
+ Due to using `Uint8Arrays` for storage, only up to 256 cell states are
130
+ supported. The same limit applies to the number of CA configs given.
131
+
132
+ ### Status
133
+
134
+ **STABLE** - used in production
135
+
136
+ [Search or submit any issues for this package](https://github.com/thi-ng/umbrella/issues?q=%5Bcellular%5D+in%3Atitle)
137
+
138
+ ### Related packages
139
+
140
+ - [@thi.ng/lsys](https://github.com/thi-ng/umbrella/tree/develop/packages/lsys) - Functional, extensible L-System architecture w/ support for probabilistic rules
141
+ - [@thi.ng/pixel](https://github.com/thi-ng/umbrella/tree/develop/packages/pixel) - Typedarray integer & float pixel buffers w/ customizable formats, blitting, drawing, convolution
142
+
143
+ ## Installation
144
+
145
+ ```bash
146
+ yarn add @thi.ng/cellular
147
+ ```
148
+
149
+ ES module import:
150
+
151
+ ```html
152
+ <script type="module" src="https://cdn.skypack.dev/@thi.ng/cellular"></script>
153
+ ```
154
+
155
+ [Skypack documentation](https://docs.skypack.dev/)
156
+
157
+ For Node.js REPL:
158
+
159
+ ```text
160
+ # with flag only for < v16
161
+ node --experimental-repl-await
162
+
163
+ > const cellular = await import("@thi.ng/cellular");
164
+ ```
165
+
166
+ Package sizes (gzipped, pre-treeshake): ESM: 1.24 KB
167
+
168
+ ## Dependencies
169
+
170
+ - [@thi.ng/api](https://github.com/thi-ng/umbrella/tree/develop/packages/api)
171
+ - [@thi.ng/checks](https://github.com/thi-ng/umbrella/tree/develop/packages/checks)
172
+ - [@thi.ng/errors](https://github.com/thi-ng/umbrella/tree/develop/packages/errors)
173
+ - [@thi.ng/random](https://github.com/thi-ng/umbrella/tree/develop/packages/random)
174
+ - [@thi.ng/transducers](https://github.com/thi-ng/umbrella/tree/develop/packages/transducers)
175
+
176
+ ## API
177
+
178
+ [Generated API docs](https://docs.thi.ng/umbrella/cellular/)
179
+
180
+ ## Code examples
181
+
182
+ ### Classic Wolfram
183
+
184
+ ```ts
185
+ import { MultiCA1D } from "@thi.ng/cellular";
186
+ import { defIndexed, intBuffer } from "@thi.ng/pixel";
187
+ import { asPPM } from "@thi.ng/pixel-io-netpbm";
188
+ import { writeFileSync } from "fs";
189
+
190
+ const WIDTH = 512;
191
+ const HEIGHT = 512;
192
+
193
+ // define standard 1D Wolfram CA (3-neighborhood, 2 states)
194
+ const ca = new MultiCA1D(
195
+ [
196
+ {
197
+ rule: 73,
198
+ // kernel can be imported as `WOLFRAM3`
199
+ kernel: [[-1, 0],[0, 0],[1, 0]],
200
+ states: 2,
201
+ reset: false,
202
+ },
203
+ ],
204
+ WIDTH
205
+ );
206
+
207
+ // seed a single cell in center
208
+ ca.current[WIDTH/2] = 1;
209
+
210
+ // create image with indexed color model (2 cell states => 2 colors)
211
+ const img = intBuffer(WIDTH, HEIGHT, defIndexed([0xff000000, 0xffffffff]));
212
+
213
+ // compute the CA for entire image
214
+ ca.updateImage(img.data, HEIGHT);
215
+
216
+ // write as PPM file
217
+ writeFileSync("export/out.ppm", asPPM(img));
218
+ ```
219
+
220
+ Result:
221
+
222
+ ![1D Wolfram CA, rule 73](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/cellular/wolfram-73.png)
223
+
224
+ ### Custom kernels & multiple rules
225
+
226
+ ```ts
227
+ import { multiColorGradient, srgb } from "@thi.ng/color";
228
+
229
+ // create CA with 2 rules/kernels (5-neighborhoods) and 64 states (max age)
230
+ const ca = new MultiCA1D(
231
+ [
232
+ {
233
+ rule: 0x73ed2ac2,
234
+ // kernel can be imported as `WOLFRAM5`
235
+ kernel: [[-2, 0], [-1, 0], [0, 0], [1, 0], [2, 0]],
236
+ states: 64,
237
+ },
238
+ {
239
+ rule: 0xef14e4ca,
240
+ // kernel can be imported as `WOLFRAM5`
241
+ kernel: [[-2, 0], [-1, 0], [0, 0], [1, 0], [2, 0]],
242
+ states: 64,
243
+ }
244
+ ],
245
+ WIDTH
246
+ );
247
+
248
+ // seed cells with 10% noise
249
+ ca.setNoise("cells", 0.1);
250
+
251
+ // set mask to stripe pattern to select both CAs
252
+ ca.setPattern("mask", WIDTH / 4, WIDTH / 2, 1, 0, WIDTH / 8);
253
+
254
+ // alternatively apply noise to the mask to create
255
+ // more uniformly hybrid/mixed results
256
+ // ca.setNoise("mask", 0.5);
257
+
258
+ // create color gradient to visualize the different cell states
259
+ // and wrap as indexed color model for pixel buffer below...
260
+ // references:
261
+ // https://docs.thi.ng/umbrella/color/modules.html#multiColorGradient
262
+ // https://docs.thi.ng/umbrella/pixel/modules.html#defIndexed
263
+ const fmt = defIndexed(
264
+ multiColorGradient(
265
+ {
266
+ num: ca.numStates,
267
+ stops: [
268
+ [0, srgb(1, 0, 0.5)],
269
+ [0.02, srgb(0.8, 1, 1)],
270
+ [1, srgb(1, 0.5, 0)],
271
+ ],
272
+ },
273
+ false
274
+ )
275
+ );
276
+
277
+ // create image / pixel buffer using above indexed color model
278
+ const img = intBuffer(WIDTH, HEIGHT, fmt);
279
+
280
+ // compute CA for full image
281
+ ca.updateImage(img.data, HEIGHT);
282
+
283
+ // export as PPM image
284
+ writeFileSync("export/out.ppm", asPPM(img));
285
+ ```
286
+
287
+ | 1st CA only | 2nd CA only |
288
+ |---------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------|
289
+ | ![](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/cellular/hybrid-a.png) | ![](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/cellular/hybrid-b.png) |
290
+ | Hybrid (stripe pattern) | Hybrid (noise) |
291
+ | ![](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/cellular/hybrid-pattern.png) | ![](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/cellular/hybrid-noise.png) |
292
+
293
+ ## Authors
294
+
295
+ Karsten Schmidt
296
+
297
+ If this project contributes to an academic publication, please cite it as:
298
+
299
+ ```bibtex
300
+ @misc{thing-cellular,
301
+ title = "@thi.ng/cellular",
302
+ author = "Karsten Schmidt",
303
+ note = "https://thi.ng/cellular",
304
+ year = 2022
305
+ }
306
+ ```
307
+
308
+ ## License
309
+
310
+ &copy; 2022 Karsten Schmidt // Apache Software License 2.0
package/api.d.ts ADDED
@@ -0,0 +1,69 @@
1
+ import type { FnN, NumericArray } from "@thi.ng/api";
2
+ export declare type Target = "cells" | "mask";
3
+ export declare type Kernel = NumericArray[];
4
+ export interface CAConfig1D {
5
+ /**
6
+ * Same as {@link CASpec1D.kernel}.
7
+ */
8
+ kernel: Kernel;
9
+ /**
10
+ * Same as {@link CASpec1D.weights}.
11
+ */
12
+ weights: bigint[];
13
+ /**
14
+ * Same as {@link CASpec1D.rule}, but always a bigint.
15
+ */
16
+ rule: bigint;
17
+ /**
18
+ * Same as {@link CASpec1D.states}.
19
+ */
20
+ states: number;
21
+ /**
22
+ * Cell state update function/behavior. Takes a current cell state, returns
23
+ * new one.
24
+ */
25
+ fn: FnN;
26
+ }
27
+ export interface CASpec1D {
28
+ /**
29
+ * Array of 2D offset vectors `[x, y]` defining the automata's neighborhood.
30
+ * `x` coordinates are horizontal offsets and positive `y` coordinates are
31
+ * used to refer to previous generations (e.g. 0 = current gen, 1 = T-1, 2 =
32
+ * T-2 etc.) and thereby providing a form of short term memory for that
33
+ * specific automata. Negative `y` coords will lead to cells being ignored.
34
+ *
35
+ * Unless {@link CASpec1D.positional} is false (default: true), the order of
36
+ * offsets _is_ important: Whenever the offset relates to a non-zero cell in the
37
+ * neighborhood, it will contribute a specific bit value to encode the
38
+ * overall state of the neighborhood, i.e. 2^k, where `k` is the array index
39
+ * of the corresponding kernel offset.
40
+ */
41
+ kernel: Kernel;
42
+ /**
43
+ * If false (default: true), the order of kernel offsets is irrelevant and
44
+ * only the count of non-zero cells in the neighborhood is used to check a
45
+ * relevant bit in the `rule` ID. E.g. if count = 3, then the 3rd LSB will
46
+ * be checked.
47
+ */
48
+ positional?: boolean;
49
+ /**
50
+ * CA replication rules encoded as bigint. The overall magnitude of these
51
+ * rule IDs depends on the size of the neighborhood kernel and will be 2^n
52
+ * bits, where `n` is the kernel size. E.g. A 5-neighborhood will offer 2^32
53
+ * = 4 billion possibilities. A 7-neighborhood corresponds to a 2^7 = 128
54
+ * bit large rule space (~10^38 possibilities!).
55
+ */
56
+ rule: bigint | number | string;
57
+ /**
58
+ * Max number of cell states (aka cell age). Note: MUST be <= 256. For
59
+ * "standard" Wolfram automata, states = 2.
60
+ */
61
+ states: number;
62
+ /**
63
+ * If true (default), cells will reset to zero once their max. age has been
64
+ * reached. Should be set to `false` for "standard" 2-state Wolfram
65
+ * automata.
66
+ */
67
+ reset?: boolean;
68
+ }
69
+ //# sourceMappingURL=api.d.ts.map
package/api.js ADDED
@@ -0,0 +1 @@
1
+ export {};
package/index.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ export * from "./api.js";
2
+ export * from "./1d.js";
3
+ //# sourceMappingURL=index.d.ts.map
package/index.js ADDED
@@ -0,0 +1,2 @@
1
+ export * from "./api.js";
2
+ export * from "./1d.js";
package/package.json ADDED
@@ -0,0 +1,96 @@
1
+ {
2
+ "name": "@thi.ng/cellular",
3
+ "version": "0.1.0",
4
+ "description": "Highly customizable 1D cellular automata, shared env, multiple rules, arbitrary sized/shaped neighborhoods, short term memory, cell states etc.",
5
+ "type": "module",
6
+ "module": "./index.js",
7
+ "typings": "./index.d.ts",
8
+ "sideEffects": false,
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "https://github.com/thi-ng/umbrella.git"
12
+ },
13
+ "homepage": "https://github.com/thi-ng/umbrella/tree/master/packages/cellular#readme",
14
+ "funding": [
15
+ {
16
+ "type": "github",
17
+ "url": "https://github.com/sponsors/postspectacular"
18
+ },
19
+ {
20
+ "type": "patreon",
21
+ "url": "https://patreon.com/thing_umbrella"
22
+ }
23
+ ],
24
+ "author": "Karsten Schmidt <k+npm@thi.ng>",
25
+ "license": "Apache-2.0",
26
+ "scripts": {
27
+ "build": "yarn clean && tsc --declaration",
28
+ "clean": "rimraf '*.js' '*.d.ts' '*.map' doc",
29
+ "doc": "typedoc --excludePrivate --excludeInternal --out doc src/index.ts",
30
+ "doc:ae": "mkdir -p .ae/doc .ae/temp && api-extractor run --local --verbose",
31
+ "doc:readme": "yarn doc:stats && tools:readme",
32
+ "doc:stats": "tools:module-stats",
33
+ "pub": "yarn npm publish --access public",
34
+ "test": "testament test"
35
+ },
36
+ "dependencies": {
37
+ "@thi.ng/api": "^8.3.7",
38
+ "@thi.ng/checks": "^3.2.0",
39
+ "@thi.ng/errors": "^2.1.7",
40
+ "@thi.ng/random": "^3.3.1",
41
+ "@thi.ng/transducers": "^8.3.4"
42
+ },
43
+ "devDependencies": {
44
+ "@microsoft/api-extractor": "^7.25.0",
45
+ "@thi.ng/testament": "^0.2.8",
46
+ "rimraf": "^3.0.2",
47
+ "tools": "^0.0.1",
48
+ "typedoc": "^0.22.17",
49
+ "typescript": "^4.7.3"
50
+ },
51
+ "keywords": [
52
+ "1d",
53
+ "automata",
54
+ "bigint",
55
+ "cellular",
56
+ "generative",
57
+ "neighborhood",
58
+ "pixel",
59
+ "rulebased",
60
+ "simulation",
61
+ "typescript"
62
+ ],
63
+ "publishConfig": {
64
+ "access": "public"
65
+ },
66
+ "browser": {
67
+ "process": false,
68
+ "setTimeout": false
69
+ },
70
+ "engines": {
71
+ "node": ">=14"
72
+ },
73
+ "files": [
74
+ "*.js",
75
+ "*.d.ts"
76
+ ],
77
+ "exports": {
78
+ ".": {
79
+ "default": "./index.js"
80
+ },
81
+ "./1d": {
82
+ "default": "./1d.js"
83
+ },
84
+ "./api": {
85
+ "default": "./api.js"
86
+ }
87
+ },
88
+ "thi.ng": {
89
+ "related": [
90
+ "lsys",
91
+ "pixel"
92
+ ],
93
+ "year": 2022
94
+ },
95
+ "gitHead": "9e516d30a1a537e027a6b3d78bf9121bc5831d31\n"
96
+ }