MayaFlux 0.1.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
Logic.cpp
Go to the documentation of this file.
1#include "Logic.hpp"
2
4
6
7//-------------------------------------------------------------------------
8// Constructors
9//-------------------------------------------------------------------------
10
11Logic::Logic(double threshold)
12 : m_mode(LogicMode::DIRECT)
13 , m_operator(LogicOperator::THRESHOLD)
14 , m_history_size(1)
15 , m_input_count(1)
16 , m_threshold(threshold)
17 , m_low_threshold(threshold * 0.9)
18 , m_high_threshold(threshold)
19 , m_edge_type(EdgeType::BOTH)
20 , m_edge_detected(false)
21 , m_hysteresis_state(false)
22 , m_temporal_time(0.0)
23{
24 m_direct_function = [this](double input) {
25 return input > m_threshold;
26 };
27}
28
29Logic::Logic(LogicOperator op, double threshold)
30 : m_mode(LogicMode::DIRECT)
31 , m_operator(op)
32 , m_history_size(1)
33 , m_input_count(1)
34 , m_threshold(threshold)
35 , m_low_threshold(threshold * 0.9)
36 , m_high_threshold(threshold)
37 , m_edge_type(EdgeType::BOTH)
38 , m_edge_detected(false)
39 , m_hysteresis_state(false)
40 , m_temporal_time(0.0)
41{
42 set_operator(op);
43}
44
46 : m_mode(LogicMode::DIRECT)
47 , m_operator(LogicOperator::CUSTOM)
48 , m_direct_function(std::move(function))
49 , m_history_size(1)
50 , m_input_count(1)
51 , m_threshold(0.5)
52 , m_low_threshold(0.45)
53 , m_high_threshold(0.5)
54 , m_edge_type(EdgeType::BOTH)
55 , m_edge_detected(false)
56 , m_hysteresis_state(false)
57 , m_temporal_time(0.0)
58{
59}
60
61Logic::Logic(MultiInputFunction function, size_t input_count)
62 : m_mode(LogicMode::MULTI_INPUT)
63 , m_operator(LogicOperator::CUSTOM)
64 , m_multi_input_function(std::move(function))
65 , m_history_size(1)
66 , m_input_count(input_count)
67 , m_threshold(0.5)
68 , m_low_threshold(0.45)
69 , m_high_threshold(0.5)
70 , m_edge_type(EdgeType::BOTH)
71 , m_edge_detected(false)
72 , m_hysteresis_state(false)
73 , m_temporal_time(0.0)
74{
75 m_input_buffer.resize(input_count, 0.0);
76}
77
78Logic::Logic(SequentialFunction function, size_t history_size)
79 : m_mode(LogicMode::SEQUENTIAL)
80 , m_operator(LogicOperator::CUSTOM)
81 , m_sequential_function(std::move(function))
82 , m_history_size(history_size)
83 , m_input_count(1)
84 , m_threshold(0.5)
85 , m_low_threshold(0.45)
86 , m_high_threshold(0.5)
87 , m_edge_type(EdgeType::BOTH)
88 , m_edge_detected(false)
89 , m_hysteresis_state(false)
90 , m_temporal_time(0.0)
91{
92 m_history.assign(history_size, false);
93}
94
96 : m_mode(LogicMode::TEMPORAL)
97 , m_operator(LogicOperator::CUSTOM)
98 , m_temporal_function(std::move(function))
99 , m_history_size(1)
100 , m_input_count(1)
101 , m_threshold(0.5)
102 , m_low_threshold(0.45)
103 , m_high_threshold(0.5)
104 , m_edge_type(EdgeType::BOTH)
105 , m_edge_detected(false)
106 , m_hysteresis_state(false)
107 , m_temporal_time(0.0)
108{
109}
110
111//-------------------------------------------------------------------------
112// Processing Methods
113//-------------------------------------------------------------------------
114
115double Logic::process_sample(double input)
116{
117 bool result = false;
118 m_edge_detected = false;
119
120 if (m_input_node) {
121 atomic_inc_modulator_count(m_input_node->m_modulator_count, 1);
122 uint32_t state = m_input_node->m_state.load();
123 if (state & Utils::NodeState::PROCESSED) {
124 input += m_input_node->get_last_output();
125 } else {
126 input = m_input_node->process_sample(input);
128 }
129 }
130
131 bool current_bool = input > m_threshold;
132 bool previous_bool = m_last_output > 0.5;
133
134 switch (m_mode) {
136 switch (m_operator) {
138 result = current_bool;
139 break;
140
142 if (input > m_high_threshold) {
143 m_hysteresis_state = true;
144 } else if (input < m_low_threshold) {
145 m_hysteresis_state = false;
146 }
147 result = m_hysteresis_state;
148 break;
149
150 case LogicOperator::EDGE: {
151 bool previous_bool_input = m_input > m_threshold;
152 if (current_bool != previous_bool_input) {
153 switch (m_edge_type) {
154 case EdgeType::RISING:
155 m_edge_detected = current_bool && !previous_bool_input;
156 break;
158 m_edge_detected = !current_bool && previous_bool_input;
159 break;
160 case EdgeType::BOTH:
161 m_edge_detected = true;
162 break;
163 }
164 }
165 result = m_edge_detected;
166 break;
167 }
168
170 result = current_bool && previous_bool;
171 break;
172
174 result = current_bool || previous_bool;
175 break;
176
178 result = current_bool != previous_bool;
179 break;
180
182 result = !current_bool;
183 break;
184
186 result = !(current_bool && previous_bool);
187 break;
188
190 result = !(current_bool || previous_bool);
191 break;
192
194 result = m_direct_function(input);
195 break;
196
197 default:
198 result = current_bool;
199 }
200 break;
201
203 bool current_bool = input > m_threshold;
204 m_history.push_front(current_bool);
205 if (m_history.size() > m_history_size) {
206 m_history.pop_back();
207 }
209 break;
210 }
211
212 case LogicMode::TEMPORAL: {
214 result = m_temporal_function(input, m_temporal_time);
215 break;
216 }
217
219 add_input(input, 0);
221 break;
222 }
223 }
224
225 m_input = input;
226 auto current = result ? 1.0 : 0.0;
227
229 notify_tick(current);
230
231 if (m_input_node) {
232 atomic_dec_modulator_count(m_input_node->m_modulator_count, 1);
234 }
235
236 m_last_output = current;
237 return m_last_output;
238}
239
240std::vector<double> Logic::process_batch(unsigned int num_samples)
241{
242 std::vector<double> output(num_samples);
243
244 for (unsigned int i = 0; i < num_samples; ++i) {
245 // For batch processing, we use 0.0 as input
246 // This is mainly useful for temporal or sequential modes
247 output[i] = process_sample(0.0);
248 }
249
250 return output;
251}
252
253double Logic::process_multi_input(const std::vector<double>& inputs)
254{
258
259 if (m_input_buffer.size() < inputs.size()) {
260 m_input_buffer.resize(inputs.size(), 0.0);
261 m_input_count = inputs.size();
262 }
263
265 m_multi_input_function = [this](const std::vector<double>& inputs) {
266 bool result = true;
267 for (const auto& input : inputs) {
268 result = result && (input > m_threshold);
269 }
270 return result;
271 };
272 }
273 }
274
275 // Copy inputs to our buffer
276 for (size_t i = 0; i < inputs.size() && i < m_input_buffer.size(); ++i) {
277 m_input_buffer[i] = inputs[i];
278 }
279
281 m_last_output = result ? 1.0 : 0.0;
282
284
285 return m_last_output;
286}
287
288void Logic::add_input(double input, size_t index)
289{
290 if (index >= m_input_buffer.size()) {
291 m_input_buffer.resize(index + 1, 0.0);
292 }
293 m_input_buffer[index] = input;
294}
295
296//-------------------------------------------------------------------------
297// Configuration Methods
298//-------------------------------------------------------------------------
299
301{
302 m_history.clear();
303 m_history.assign(m_history_size, false);
304 m_edge_detected = false;
305 m_last_output = 0.0;
306 m_hysteresis_state = false;
307 m_temporal_time = 0.0;
308 m_input_buffer.assign(m_input_count, 0.0);
309}
310
311void Logic::set_threshold(double threshold, bool create_default_direct_function)
312{
313 m_threshold = threshold;
314 m_high_threshold = threshold;
315 m_low_threshold = threshold * 0.9; // Default hysteresis
316
317 if (m_operator == LogicOperator::THRESHOLD && m_mode == LogicMode::DIRECT && create_default_direct_function) {
318 m_direct_function = [this](double input) {
319 return input > m_threshold;
320 };
321 }
322}
323
324void Logic::set_hysteresis(double low_threshold, double high_threshold, bool create_default_direct_function)
325{
326 m_low_threshold = low_threshold;
327 m_high_threshold = high_threshold;
328 m_threshold = high_threshold; // For compatibility with other methods
329
330 if (m_operator == LogicOperator::HYSTERESIS && m_mode == LogicMode::DIRECT && create_default_direct_function) {
331 m_direct_function = [this](double input) {
332 if (input > m_high_threshold) {
333 m_hysteresis_state = true;
334 } else if (input < m_low_threshold) {
335 m_hysteresis_state = false;
336 }
337 return m_hysteresis_state;
338 };
339 }
340}
341
342void Logic::set_edge_detection(EdgeType type, double threshold)
343{
344 m_edge_type = type;
345 m_threshold = threshold;
347}
348
349void Logic::set_operator(LogicOperator op, bool create_default_direct_function)
350{
351 m_operator = op;
352
353 if (create_default_direct_function) {
354 switch (op) {
356 m_direct_function = [this](double input) {
357 bool current = input > m_threshold;
358 bool previous = m_last_output > 0.5;
359 return current && previous;
360 };
361 break;
362
364 m_direct_function = [this](double input) {
365 bool current = input > m_threshold;
366 bool previous = m_last_output > 0.5;
367 return current || previous;
368 };
369 break;
370
372 m_direct_function = [this](double input) {
373 bool current = input > m_threshold;
374 bool previous = m_last_output > 0.5;
375 return current != previous;
376 };
377 break;
378
380 m_direct_function = [this](double input) {
381 return !(input > m_threshold);
382 };
383 break;
384
386 m_direct_function = [this](double input) {
387 bool current = input > m_threshold;
388 bool previous = m_last_output > 0.5;
389 return !(current && previous);
390 };
391 break;
392
394 m_direct_function = [this](double input) {
395 bool current = input > m_threshold;
396 bool previous = m_last_output > 0.5;
397 return !(current || previous);
398 };
399 break;
400
402 m_direct_function = [this](double input) {
403 return input > m_threshold;
404 };
405 break;
406
408 m_direct_function = [this](double input) {
409 if (input > m_high_threshold) {
410 m_hysteresis_state = true;
411 } else if (input < m_low_threshold) {
412 m_hysteresis_state = false;
413 }
414 return m_hysteresis_state;
415 };
416 break;
417
419 // Edge detection is handled in process_sample
420 break;
421
423 // Custom function should be set directly
424 break;
425 }
426 }
427}
428
435
436void Logic::set_multi_input_function(MultiInputFunction function, size_t input_count)
437{
438 m_multi_input_function = std::move(function);
441 m_input_count = input_count;
442
443 // Resize input buffer if needed
444 if (m_input_buffer.size() != input_count) {
445 m_input_buffer.resize(input_count, 0.0);
446 }
447}
448
449void Logic::set_sequential_function(SequentialFunction function, size_t history_size)
450{
451 m_sequential_function = std::move(function);
454
455 if (history_size != m_history_size) {
456 m_history_size = history_size;
457 m_history.clear();
458 m_history.assign(history_size, false);
459 }
460}
461
463{
464 m_temporal_function = std::move(function);
467 // Reset temporal time when changing function
468 m_temporal_time = 0.0;
469}
470
471void Logic::set_initial_conditions(const std::vector<bool>& initial_values)
472{
473 m_history.clear();
474
475 for (const auto& value : initial_values) {
476 m_history.push_back(value);
477 }
478
479 if (m_history.size() < m_history_size) {
480 m_history.resize(m_history_size, false);
481 } else if (m_history.size() > m_history_size) {
483 }
484}
485
486std::unique_ptr<NodeContext> Logic::create_context(double value)
487{
488 if (m_gpu_compatible) {
489 return std::make_unique<LogicContextGpu>(
490 value,
491 m_mode,
493 m_history,
499 }
500
501 return std::make_unique<LogicContext>(
502 value,
503 m_mode,
505 m_history,
510}
511
512void Logic::notify_tick(double value)
513{
515 bool state_changed = (value != m_last_output);
516
517 for (const auto& cb : m_all_callbacks) {
518 bool should_call = false;
519
520 switch (cb.event_type) {
522 should_call = true;
523 break;
524
526 should_call = value;
527 break;
528
530 should_call = !value;
531 break;
532
534 should_call = state_changed;
535 break;
536
538 should_call = state_changed && value;
539 break;
540
542 should_call = state_changed && !value;
543 break;
544
546 should_call = cb.condition && cb.condition.value()(*m_last_context);
547 break;
548 }
549
550 if (should_call) {
551 cb.callback(*m_last_context);
552 }
553 }
554}
555
556void Logic::on_tick(const NodeHook& callback)
557{
559}
560
561void Logic::on_tick_if(const NodeHook& callback, const NodeCondition& condition)
562{
563 add_callback(callback, LogicEventType::CONDITIONAL, condition);
564}
565
566void Logic::while_true(const NodeHook& callback)
567{
569}
570
571void Logic::while_false(const NodeHook& callback)
572{
574}
575
576void Logic::on_change(const NodeHook& callback)
577{
579}
580
581void Logic::on_change_to(const NodeHook& callback, bool target_state)
582{
583 add_callback(callback, target_state ? LogicEventType::TRUE : LogicEventType::FALSE);
584}
585
586bool Logic::remove_hook(const NodeHook& callback)
587{
588 auto it = std::remove_if(m_all_callbacks.begin(), m_all_callbacks.end(),
589 [&callback](const LogicCallback& cb) {
590 return cb.callback.target_type() == callback.target_type();
591 });
592
593 if (it != m_all_callbacks.end()) {
594 m_all_callbacks.erase(it, m_all_callbacks.end());
595 return true;
596 }
597 return false;
598}
599
601{
602 auto it = std::remove_if(m_all_callbacks.begin(), m_all_callbacks.end(),
603 [&callback](const LogicCallback& cb) {
604 return cb.event_type == LogicEventType::CONDITIONAL && cb.condition && cb.condition->target_type() == callback.target_type();
605 });
606
607 if (it != m_all_callbacks.end()) {
608 m_all_callbacks.erase(it, m_all_callbacks.end());
609 return true;
610 }
611 return false;
612}
613
615{
616 auto it = std::remove_if(m_all_callbacks.begin(), m_all_callbacks.end(),
617 [type](const LogicCallback& cb) {
618 return cb.event_type == type;
619 });
620 m_all_callbacks.erase(it, m_all_callbacks.end());
621}
622
636
650
651}
SequentialFunction m_sequential_function
Function for sequential mode.
Definition Logic.hpp:563
void set_direct_function(DirectFunction function)
Sets a custom combinational logic function.
Definition Logic.cpp:429
void set_initial_conditions(const std::vector< bool > &initial_values)
Preloads the state history buffer.
Definition Logic.cpp:471
void set_sequential_function(SequentialFunction function, size_t history_size)
Sets a custom state-based evaluation function.
Definition Logic.cpp:449
TemporalFunction m_temporal_function
Function for temporal mode.
Definition Logic.hpp:564
DirectFunction m_direct_function
Function for direct mode.
Definition Logic.hpp:561
void reset()
Resets internal state to initial conditions.
Definition Logic.cpp:300
size_t m_history_size
Maximum size of the history buffer.
Definition Logic.hpp:566
void on_change_to(const NodeHook &callback, bool target_state)
Registers a callback for when output changes to a specific state.
Definition Logic.cpp:581
EdgeType m_edge_type
Type of edge to detect.
Definition Logic.hpp:571
Logic(double threshold=0.5)
Constructs a Logic node with threshold quantization.
Definition Logic.cpp:11
double process_sample(double input=0.) override
Processes a single input sample through the logic function.
Definition Logic.cpp:115
double m_threshold
Threshold for boolean conversion.
Definition Logic.hpp:568
void remove_hooks_of_type(LogicEventType type)
Definition Logic.cpp:614
std::deque< bool > m_history
Buffer of input values for feedforward mode.
Definition Logic.hpp:565
void on_tick_if(const NodeHook &callback, const NodeCondition &condition) override
Registers a conditional callback for generated samples.
Definition Logic.cpp:561
std::function< bool(double)> DirectFunction
Function type for stateless boolean evaluation.
Definition Logic.hpp:167
double m_temporal_time
Time tracking for temporal mode.
Definition Logic.hpp:574
void set_temporal_function(TemporalFunction function)
Sets a custom time-dependent evaluation function.
Definition Logic.cpp:462
double m_high_threshold
High threshold for hysteresis.
Definition Logic.hpp:570
std::function< bool(const std::deque< bool > &)> SequentialFunction
Function type for state-based evaluation.
Definition Logic.hpp:177
double m_input
Current input value for multi-input mode.
Definition Logic.hpp:576
std::vector< double > m_input_buffer
Definition Logic.hpp:575
void set_edge_detection(EdgeType type, double threshold=0.5)
Configures digital transition detection.
Definition Logic.cpp:342
std::shared_ptr< Node > m_input_node
Input node for processing.
Definition Logic.hpp:577
LogicOperator m_operator
Current logic operator.
Definition Logic.hpp:560
std::function< bool(const std::vector< double > &)> MultiInputFunction
Function type for parallel input evaluation.
Definition Logic.hpp:172
void set_operator(LogicOperator op, bool create_default_direct_function=false)
Sets the boolean operation to perform.
Definition Logic.cpp:349
void add_callback(const NodeHook &callback, LogicEventType type, const std::optional< NodeCondition > &condition=std::nullopt)
Adds a callback to the list of all callbacks.
Definition Logic.hpp:588
double m_low_threshold
Low threshold for hysteresis.
Definition Logic.hpp:569
MultiInputFunction m_multi_input_function
Function for recursive/feedforward mode.
Definition Logic.hpp:562
std::deque< bool > m_saved_history
Definition Logic.hpp:603
bool m_edge_detected
Whether an edge was detected in the last processing.
Definition Logic.hpp:572
bool remove_conditional_hook(const NodeCondition &callback) override
Removes a previously registered conditional callback.
Definition Logic.cpp:600
std::vector< LogicCallback > m_all_callbacks
Collection of all callback functions.
Definition Logic.hpp:601
void set_hysteresis(double low_threshold, double high_threshold, bool create_default_direct_function=false)
Configures noise-resistant binary quantization with memory.
Definition Logic.cpp:324
void set_multi_input_function(MultiInputFunction function, size_t input_count)
Sets a custom parallel input evaluation function.
Definition Logic.cpp:436
std::vector< double > process_batch(unsigned int num_samples) override
Processes multiple samples in batch mode.
Definition Logic.cpp:240
void save_state() override
Saves the node's current state for later restoration Recursively cascades through all connected modul...
Definition Logic.cpp:623
bool m_hysteresis_state
State for hysteresis operator.
Definition Logic.hpp:573
void on_tick(const NodeHook &callback) override
Registers a callback for every generated sample.
Definition Logic.cpp:556
void on_change(const NodeHook &callback)
Registers a callback for any state change (true↔false)
Definition Logic.cpp:576
std::unique_ptr< NodeContext > create_context(double value) override
Creates a context object for callbacks.
Definition Logic.cpp:486
double process_multi_input(const std::vector< double > &inputs)
Processes multiple parallel inputs.
Definition Logic.cpp:253
LogicMode m_mode
Current processing mode.
Definition Logic.hpp:559
std::function< bool(double, double)> TemporalFunction
Function type for time-dependent evaluation.
Definition Logic.hpp:182
void while_false(const NodeHook &callback)
Registers a callback that executes continuously while output is false.
Definition Logic.cpp:571
void restore_state() override
Restores the node's state from the last save Recursively cascades through all connected modulator nod...
Definition Logic.cpp:637
void notify_tick(double value) override
Notifies all registered callbacks about a new sample.
Definition Logic.cpp:512
size_t m_input_count
Expected number of inputs for multi-input mode.
Definition Logic.hpp:567
bool remove_hook(const NodeHook &callback) override
Removes a previously registered callback.
Definition Logic.cpp:586
void add_input(double input, size_t index)
Definition Logic.cpp:288
void set_threshold(double threshold, bool create_default_direct_function=false)
Sets the decision boundary for binary quantization.
Definition Logic.cpp:311
void while_true(const NodeHook &callback)
Registers a callback that executes continuously while output is true.
Definition Logic.cpp:566
double m_last_output
The most recent sample value generated by this oscillator.
Definition Node.hpp:378
bool m_fire_events_during_snapshot
Internal flag controlling whether notify_tick fires during state snapshots Default: false (events don...
Definition Node.hpp:448
bool m_gpu_compatible
Flag indicating if the node supports GPU processing This flag is set by derived classes to indicate w...
Definition Node.hpp:387
std::unique_ptr< NodeContext > m_last_context
The last context object created for callbacks.
Definition Node.hpp:396
std::span< const float > get_gpu_data_buffer() const
Provides access to the GPU data buffer.
Definition Node.cpp:78
uint32_t get_sample_rate()
Gets the sample rate from the default engine.
Definition Config.cpp:46
EdgeType
Digital transition patterns to detect.
Definition Logic.hpp:40
@ FALLING
High-to-low transition (1→0)
@ RISING
Low-to-high transition (0→1)
LogicMode
Defines the computational model for digital signal evaluation.
Definition Logic.hpp:11
@ SEQUENTIAL
State-based evaluation using history of inputs (sequential logic)
@ DIRECT
Stateless evaluation of current input only (combinational logic)
@ TEMPORAL
Time-dependent evaluation with timing constraints.
@ MULTI_INPUT
Parallel evaluation of multiple input signals.
LogicEventType
Events that can trigger callbacks.
Definition Logic.hpp:50
LogicOperator
Digital operators for boolean computation.
Definition Logic.hpp:22
@ NOT
Logical NOT - inverts the input.
@ NOR
Logical NOR - inverted OR operation.
@ OR
Logical OR - true when any input is true.
@ NAND
Logical NAND - inverted AND operation.
@ THRESHOLD
Binary quantization - true when input exceeds threshold.
@ AND
Logical AND - true only when all inputs are true.
@ EDGE
Transition detector - identifies state changes.
@ HYSTERESIS
Threshold with memory - prevents rapid oscillation at boundary.
@ CUSTOM
User-defined boolean function.
@ XOR
Logical XOR - true when odd number of inputs are true.
std::function< void(NodeContext &)> NodeHook
Callback function type for node processing events.
Definition NodeUtils.hpp:25
void atomic_add_flag(std::atomic< Utils::NodeState > &state, Utils::NodeState flag)
Atomically adds a flag to a node state.
Definition NodeUtils.cpp:96
void try_reset_processed_state(std::shared_ptr< Node > node)
Attempts to reset the processed state of a node.
void atomic_inc_modulator_count(std::atomic< uint32_t > &count, int amount)
Atomically increments the modulator count by a specified amount.
std::function< bool(NodeContext &)> NodeCondition
Predicate function type for conditional callbacks.
Definition NodeUtils.hpp:43
void atomic_dec_modulator_count(std::atomic< uint32_t > &count, int amount)
Atomically decrements the modulator count by a specified amount.
@ PROCESSED
Node has been processed this cycle.
Definition Utils.hpp:34