9 constexpr size_t MAX_TABLE_ARITY = 20;
10 constexpr size_t MAX_STATE_ARITY = 6;
11 constexpr uint32_t DEFAULT_SEED = 2463534242U;
12 constexpr double UINT32_SPAN = 4294967296.0;
14 bool rises(
bool high,
double& latched)
noexcept
16 const bool edge = high && latched <= 0.5;
17 latched = high ? 1.0 : 0.0;
21 size_t index_of(
double value)
noexcept
23 return static_cast<size_t>(std::max(
value, 0.0));
26 uint32_t word_of(
double value)
noexcept
28 return static_cast<uint32_t
>(std::clamp(
value, 0.0, UINT32_SPAN - 1.0));
35 arity = std::min(arity, MAX_STATE_ARITY);
37 std::vector<double> state(1 + (
size_t { 1 } << arity), 0.0);
38 state.front() =
static_cast<double>(arity);
40 for (
size_t i = 1; i < state.size(); ++i)
41 state[i] =
static_cast<double>((rule >> (i - 1)) & 1U);
45bool truth_table(std::span<const bool> history, std::span<const double> coefs)
noexcept
50 const size_t arity = index_of(coefs.front());
51 if (arity > MAX_TABLE_ARITY || coefs.size() < 1 + (
size_t { 1 } << arity))
55 for (
size_t i = 0; i < arity && i < history.size(); ++i) {
57 pattern |=
size_t { 1 } << i;
59 return coefs[1 + pattern] > 0.5;
62bool count_at_least(std::span<const bool> history, std::span<const double> coefs)
noexcept
67 const size_t n = std::min(index_of(coefs[0]), history.size());
68 const auto set =
static_cast<size_t>(std::count(history.begin(), history.begin() +
static_cast<std::ptrdiff_t
>(n),
true));
69 return set >= index_of(coefs[1]);
74 return { low, high, 0.0 };
84 else if (
input < coefs[0])
86 return coefs[2] > 0.5;
99 if (rises(
input > coefs[0], coefs[1]))
100 coefs[2] = coefs[2] > 0.5 ? 0.0 : 1.0;
101 return coefs[2] > 0.5;
106 return {
threshold, 0.0, 0.0,
static_cast<double>(n),
static_cast<double>(
offset), 0.0 };
111 if (coefs.size() < 6)
114 const bool high =
input > coefs[0];
115 if (rises(high, coefs[1])) {
116 const size_t n = std::max<size_t>(index_of(coefs[3]), 1);
117 const size_t edge = index_of(coefs[2]);
118 coefs[5] = (edge % n) == (index_of(coefs[4]) % n) ? 1.0 : 0.0;
119 coefs[2] =
static_cast<double>(edge + 1);
121 return high && coefs[5] > 0.5;
126 return {
threshold, 0.0, probability,
static_cast<double>(seed == 0 ? DEFAULT_SEED : seed), 0.0 };
131 if (coefs.size() < 5)
134 const bool high =
input > coefs[0];
135 if (rises(high, coefs[1])) {
136 uint32_t state = word_of(coefs[3]);
138 state = DEFAULT_SEED;
140 coefs[3] =
static_cast<double>(state);
141 coefs[4] =
static_cast<double>(state) / UINT32_SPAN < coefs[2] ? 1.0 : 0.0;
143 return high && coefs[4] > 0.5;
148 return {
threshold, 0.0,
static_cast<double>(taps),
static_cast<double>(seed == 0 ? 1U : seed) };
153 if (coefs.size() < 4)
156 uint32_t reg = word_of(coefs[3]);
157 if (rises(
input > coefs[0], coefs[1])) {
160 const bool fell_out = (reg & 1U) != 0U;
163 reg ^= word_of(coefs[2]);
164 coefs[3] =
static_cast<double>(reg);
166 return (reg & 1U) != 0U;
171 const size_t states = table.size() / 4;
173 std::vector<double> state(3 + 4 * states, 0.0);
175 state[1] =
static_cast<double>(states);
176 state[2] =
static_cast<double>(initial);
178 std::copy_n(table.begin(),
static_cast<std::ptrdiff_t
>(4 * states), state.begin() + 3);
184 if (coefs.size() < 3)
187 const size_t states = index_of(coefs[1]);
188 if (states == 0 || coefs.size() < 3 + 4 * states)
191 size_t current = index_of(coefs[2]);
195 const size_t row = 3 + 4 *
current + (
input > coefs[0] ? 2 : 0);
196 const size_t next = index_of(coefs[row]);
197 coefs[2] =
static_cast<double>(next < states ? next : 0);
198 return coefs[row + 1] > 0.5;
203 std::vector<double>
out(steps, 0.0);
207 pulses = std::min(pulses, steps);
208 for (
size_t i = 0; i < steps; ++i) {
209 const size_t position = (i + rotation) % steps;
210 out[i] = (
position * pulses) % steps < pulses ? 1.0 : 0.0;
222 return { std::numeric_limits<double>::lowest(), period,
threshold };
227 if (coefs.size() < 3)
230 if (
input > coefs[2] && time - coefs[0] >= coefs[1]) {
239 return {
threshold, 0.0, 0.0, duration };
244 if (coefs.size() < 4)
247 if (rises(
input > coefs[0], coefs[1]))
248 coefs[2] = time + coefs[3];
249 return time < coefs[2];
257bool set_reset_latch(
const std::vector<double>& inputs, std::span<double> coefs)
noexcept
259 if (inputs.size() < 2 || coefs.size() < 2)
262 if (inputs[1] > coefs[0])
264 else if (inputs[0] > coefs[0])
266 return coefs[1] > 0.5;
271 return { margin, 0.0 };
274bool comparator(
const std::vector<double>& inputs, std::span<double> coefs)
noexcept
276 if (inputs.size() < 2 || coefs.size() < 2)
279 const double difference = inputs[0] - inputs[1];
280 if (difference > coefs[0])
282 else if (difference < -coefs[0])
284 return coefs[1] > 0.5;
289 if (inputs.size() < 3)
291 return inputs[0] > inputs[1] && inputs[0] < inputs[2];
296 return {
threshold,
static_cast<double>(k) };
299bool signals_at_least(
const std::vector<double>& inputs, std::span<const double> coefs)
noexcept
301 if (coefs.size() < 2)
305 const auto high =
static_cast<size_t>(std::count_if(inputs.begin(), inputs.end(),
306 [
threshold](
double v) { return v > threshold; }));
307 return high >= index_of(coefs[1]);
312 arity = std::min(arity, MAX_STATE_ARITY);
314 std::vector<double> state(2 + (
size_t { 1 } << arity), 0.0);
316 state[1] =
static_cast<double>(arity);
318 for (
size_t i = 2; i < state.size(); ++i)
319 state[i] =
static_cast<double>((rule >> (i - 2)) & 1U);
323bool input_truth_table(
const std::vector<double>& inputs, std::span<const double> coefs)
noexcept
325 if (coefs.size() < 2)
328 const size_t arity = index_of(coefs[1]);
329 if (arity > MAX_TABLE_ARITY || coefs.size() < 2 + (
size_t { 1 } << arity))
333 for (
size_t i = 0; i < arity && i < inputs.size(); ++i) {
334 if (inputs[i] > coefs[0])
335 pattern |=
size_t { 1 } << i;
337 return coefs[2 + pattern] > 0.5;
342 std::vector<double> state(4 +
length, 0.0);
344 state[2] =
static_cast<double>(
length);
345 state[3] =
static_cast<double>(tap);
351 if (inputs.size() < 2 || coefs.size() < 4)
354 const size_t length = index_of(coefs[2]);
358 const auto stages = coefs.subspan(4,
length);
359 if (rises(inputs[0] > coefs[0], coefs[1])) {
360 for (
size_t i =
length - 1; i > 0; --i)
361 stages[i] = stages[i - 1];
362 stages[0] = inputs[1] > coefs[0] ? 1.0 : 0.0;
364 return stages[std::min(index_of(coefs[3]),
length - 1)] > 0.5;
Pure decision functions of bits and an array of numbers.
Core::GlobalInputConfig input
std::optional< glm::vec3 > position
Pure functions of a newest-first window and an array of numbers.
std::vector< float > * out
bool one_shot(double input, double time, std::span< double > coefs) noexcept
Monostable: every rise of the input opens the output for a fixed time.
bool bernoulli_gate(double input, std::span< double > coefs) noexcept
Probabilistic gate: each pulse passes with the given probability.
bool truth_table(std::span< const bool > history, std::span< const double > coefs) noexcept
Any boolean function of the last bits, as a table.
std::vector< double > state_machine_state(std::span< const double > table, double threshold, size_t initial)
Builds the array state_machine reads and writes.
std::vector< double > truth_table_state(size_t arity, uint64_t rule)
Builds the array truth_table reads.
uint32_t xorshift32(uint32_t state) noexcept
One step of the 32-bit xorshift generator.
bool comparator(const std::vector< double > &inputs, std::span< double > coefs) noexcept
Signal against signal: true once slot 0 exceeds slot 1 by the margin.
std::vector< double > signals_at_least_state(size_t k, double threshold)
Builds the array signals_at_least reads.
std::vector< double > bernoulli_gate_state(double probability, uint32_t seed, double threshold)
Builds the array bernoulli_gate reads and writes.
std::vector< double > edge_divider_state(size_t n, size_t offset, double threshold)
Builds the array edge_divider reads and writes.
bool window_comparator(const std::vector< double > &inputs, std::span< const double >) noexcept
True while slot 0 lies strictly between slot 1 and slot 2.
bool step_pattern(double input, std::span< double > coefs) noexcept
A table of bits advanced by the rises of the input.
bool count_at_least(std::span< const bool > history, std::span< const double > coefs) noexcept
True when at least k of the last n bits are set.
std::vector< double > hysteresis_gate_state(double low, double high)
Builds the array hysteresis_gate reads and writes.
std::vector< double > comparator_state(double margin)
Builds the array comparator reads and writes.
std::vector< double > galois_lfsr_state(uint32_t taps, uint32_t seed, double threshold)
Builds the array galois_lfsr reads and writes.
bool refractory_gate(double input, double time, std::span< double > coefs) noexcept
Fires while the input is high, then ignores it for a period.
std::vector< double > maximally_even_sequence(size_t pulses, size_t steps, size_t rotation)
The maximally even placement of pulses among steps, as a 0 or 1 table.
double step_sequence(std::span< const double > window, std::span< double > coefs) noexcept
Table of values advanced by a trigger.
bool rising_toggle(double input, std::span< double > coefs) noexcept
Flip-flop: the output inverts on every rise of the input.
bool clocked_register(const std::vector< double > &inputs, std::span< double > coefs) noexcept
Shift register: slot 1 is sampled into it on every rise of slot 0.
std::vector< double > refractory_gate_state(double period, double threshold)
Builds the array refractory_gate reads and writes.
bool state_machine(double input, std::span< double > coefs) noexcept
Mealy machine: the state and the input bit pick the next state and the output.
bool input_truth_table(const std::vector< double > &inputs, std::span< const double > coefs) noexcept
Any boolean function of the input slots, as a table.
bool signals_at_least(const std::vector< double > &inputs, std::span< const double > coefs) noexcept
True when at least k of the input slots are high.
std::vector< double > input_truth_table_state(size_t arity, uint64_t rule, double threshold)
Builds the array input_truth_table reads.
std::vector< double > clocked_register_state(size_t length, size_t tap, double threshold)
Builds the array clocked_register reads and writes.
std::vector< double > set_reset_latch_state(double threshold)
Builds the array set_reset_latch reads and writes.
std::vector< double > one_shot_state(double duration, double threshold)
Builds the array one_shot reads and writes.
bool galois_lfsr(double input, std::span< double > coefs) noexcept
Linear feedback shift register clocked by the rises of the input.
bool set_reset_latch(const std::vector< double > &inputs, std::span< double > coefs) noexcept
Memory cell: slot 0 sets it, slot 1 resets it, reset wins.
bool edge_divider(double input, std::span< double > coefs) noexcept
Gate divider: the input passes only during every n-th pulse.
bool hysteresis_gate(double input, std::span< double > coefs) noexcept
Schmitt trigger: engages above high, releases below low, holds between.
std::vector< double > rising_toggle_state(double threshold)
Builds the array rising_toggle reads and writes.