1mod impl_neural;
14mod impl_vnode;
15
16use crate::ctx::ActorContext;
17use crate::drivers::{Driver, NeuralPlant, RawDriver, WolframPlant};
18use crate::mem::TopoLedger;
19use crate::operators::{Agent, Observer, Operator, OperatorKind};
20use crate::surface::{PointKind, SurfaceNetwork};
21use crate::traits::Actor;
22use crate::types::VirtualMemoryAnalysis;
23use rstmt::nrt::{LPR, Triad, Triads};
24use rstmt::{Aspn as Note, PitchMod};
25
26use ndarray::Array2;
27use num_traits::{Float, FromPrimitive, NumAssign, ToPrimitive};
28use scsys::Id;
29use std::collections::HashMap;
30use std::time::Instant;
31
32pub type NeuralNode<T = f32> = VNode<NeuralPlant<T>, T>;
34pub type WolframNode<T = f32> = VNode<WolframPlant, T>;
36
37#[derive(Clone, Debug)]
57pub struct VNode<D, T = f32>
58where
59 D: RawDriver<Triad>,
60{
61 pub(crate) id: Id,
62 pub(crate) driver: D,
64 pub(crate) operator: Operator<T>,
66 pub(crate) store: TopoLedger<T>,
68 pub(crate) surface: Option<SurfaceNetwork<T>>,
70 pub(crate) prev_weight_changes: Option<(Array2<T>, Array2<T>)>,
72 pub(crate) critical_points: HashMap<String, usize>,
74 pub(crate) tonic_history: Vec<usize>,
76 pub(crate) last_context: Option<(ActorContext<T>, Instant)>,
78}
79
80impl<D, T> VNode<D, T>
81where
82 D: RawDriver<Triad>,
83{
84 pub fn new() -> Self
86 where
87 D: Default,
88 T: Float + FromPrimitive + ToPrimitive,
89 {
90 let plant = D::default();
91 Self::from_driver(plant)
92 }
93 pub fn from_driver(plant: D) -> Self
95 where
96 T: Float + FromPrimitive + ToPrimitive,
97 {
98 let memory = TopoLedger::new();
99 let id: Id;
100 #[cfg(feature = "rand")]
101 {
102 id = Id::<u128>::random().map(|id| id as usize);
103 }
104 #[cfg(not(feature = "rand"))]
105 {
106 id = Id::atomic();
107 }
108 let mut vnode = VNode {
109 id,
110 critical_points: HashMap::new(),
111 driver: plant,
112 last_context: None,
113 operator: Operator::Observer(Observer::new()),
114 prev_weight_changes: None,
115 store: memory,
116 surface: None,
117 tonic_history: Vec::new(),
118 };
119
120 vnode.record_state();
122
123 vnode
124 }
125 pub fn from_headspace(headspace: Triad) -> Self
127 where
128 D: Driver<Triad>,
129 T: Float + FromPrimitive + ToPrimitive,
130 {
131 let plant = D::from_headspace(headspace);
132 Self::from_driver(plant)
133 }
134 pub const fn id(&self) -> Id {
136 self.id
137 }
138 pub fn class(&self) -> Triads {
140 self.driver().headspace().class()
141 }
142 pub const fn critical_points(&self) -> &HashMap<String, usize> {
144 &self.critical_points
145 }
146 pub const fn critical_points_mut(&mut self) -> &mut HashMap<String, usize> {
148 &mut self.critical_points
149 }
150 pub const fn driver(&self) -> &D {
152 &self.driver
153 }
154 pub const fn driver_mut(&mut self) -> &mut D {
156 &mut self.driver
157 }
158
159 #[inline]
161 pub fn headspace_mut(&mut self) -> &mut Triad {
162 self.driver.headspace_mut()
163 }
164 pub fn last_context(&self) -> Option<&(ActorContext<T>, Instant)> {
166 self.last_context.as_ref()
167 }
168 pub fn last_context_mut(&mut self) -> Option<&mut (ActorContext<T>, Instant)> {
170 self.last_context.as_mut()
171 }
172 pub const fn store(&self) -> &TopoLedger<T> {
174 &self.store
175 }
176 pub const fn store_mut(&mut self) -> &mut TopoLedger<T> {
178 &mut self.store
179 }
180 #[deprecated(since = "0.3.0", note = "use `store` instead")]
181 pub const fn memory(&self) -> &TopoLedger<T> {
182 &self.store
183 }
184 #[deprecated(since = "0.3.0", note = "use `store_mut` instead")]
185 pub const fn memory_mut(&mut self) -> &mut TopoLedger<T> {
186 &mut self.store
187 }
188 pub const fn operator(&self) -> &Operator<T> {
190 &self.operator
191 }
192 pub const fn operator_mut(&mut self) -> &mut Operator<T> {
194 &mut self.operator
195 }
196 pub fn surface(&self) -> Option<&SurfaceNetwork<T>> {
198 self.surface.as_ref()
199 }
200 pub fn surface_mut(&mut self) -> Option<&mut SurfaceNetwork<T>> {
202 self.surface.as_mut()
203 }
204 pub const fn tonic_history(&self) -> &Vec<usize> {
206 &self.tonic_history
207 }
208 pub const fn tonic_history_mut(&mut self) -> &mut Vec<usize> {
210 &mut self.tonic_history
211 }
212 pub fn set_id(&mut self, id: Id) -> &mut Self {
214 self.id = id;
215 self
216 }
217 pub fn set_critical_points(&mut self, critical_points: HashMap<String, usize>) -> &mut Self {
219 self.critical_points = critical_points;
220 self
221 }
222 pub fn set_driver(&mut self, driver: D) -> &mut Self
224 where
225 T: Float + FromPrimitive + ToPrimitive,
226 {
227 self.driver = driver;
228 self
229 }
230 pub fn set_operator(&mut self, operator: Operator<T>) -> &mut Self {
232 self.operator = operator;
233 self
234 }
235 pub fn set_store(&mut self, store: TopoLedger<T>) -> &mut Self {
237 self.store = store;
238 self
239 }
240 pub fn set_surface(&mut self, surface: Option<SurfaceNetwork<T>>) -> &mut Self {
242 self.surface = surface;
243 self
244 }
245 pub fn set_tonic_history(&mut self, tonic_history: Vec<usize>) -> &mut Self {
247 self.tonic_history = tonic_history;
248 self
249 }
250 pub fn with_critical_points(self, critical_points: HashMap<String, usize>) -> Self {
252 Self {
253 critical_points,
254 ..self
255 }
256 }
257 pub fn with_driver(self, driver: D) -> Self {
259 Self { driver, ..self }
260 }
261 pub fn with_id(self, id: Id) -> Self {
263 Self { id, ..self }
264 }
265 pub fn with_operator(self, operator: Operator<T>) -> Self {
267 Self { operator, ..self }
268 }
269 pub fn with_store(self, store: TopoLedger<T>) -> Self {
271 Self { store, ..self }
272 }
273 pub fn with_surface(self, surface: Option<SurfaceNetwork<T>>) -> Self {
275 Self { surface, ..self }
276 }
277 pub fn with_tonic_history(self, tonic_history: Vec<usize>) -> Self {
279 Self {
280 tonic_history,
281 ..self
282 }
283 }
284 pub fn add_critical_point(&mut self, name: PointKind, pitch_class: usize) -> Option<usize> {
287 self.critical_points_mut()
288 .insert(name.to_string(), pitch_class.pmod())
289 }
290 pub fn calculate_centroid(&self) -> Option<[T; 2]>
292 where
293 T: num_traits::Float + num_traits::FromPrimitive,
294 {
295 self.driver().headspace().centroid()
296 }
297 pub fn headspace(&self) -> &Triad {
299 self.driver().headspace()
300 }
301 pub const fn kind(&self) -> OperatorKind {
303 match self.operator {
304 Operator::Agent(_) => OperatorKind::Agent,
305 Operator::Observer(_) => OperatorKind::Observer,
306 }
307 }
308 pub fn record_navigation(&mut self, origin: &Triad, transforms_used: &[LPR])
310 where
311 T: Float + FromPrimitive + ToPrimitive,
312 {
313 let to_triad = *self.driver().headspace();
314
315 self.store_mut()
316 .record_navigation(&origin.notes(), &to_triad.notes(), transforms_used);
317 }
318 pub fn remove_critical_point(&mut self, name: PointKind) -> Option<usize> {
320 self.critical_points_mut().remove(&name.to_string())
321 }
322 #[deprecated(since = "0.3.0", note = "use `total_critical_points` instead")]
323 pub fn critical_point_count(&self) -> usize {
324 self.critical_points().len()
325 }
326 #[deprecated(since = "0.3.0", note = "use `total_features` instead")]
327 pub fn feature_count(&self) -> usize {
328 self.store().count_features()
329 }
330 pub fn total_critical_points(&self) -> usize {
332 self.critical_points().len()
333 }
334 pub fn total_features(&self) -> usize {
336 self.store().count_features()
337 }
338 pub fn get_notes(&self) -> [usize; 3] {
340 self.driver().headspace().notes()
341 }
342 pub fn get_tonic(&self) -> Note {
344 let class = self.driver().headspace().root();
345 let octave = self.driver().headspace().octave();
346 Note::new(class, octave)
347 }
348 pub fn has_surface_network(&self) -> bool {
350 self.surface().is_some()
351 }
352 pub fn record_state(&mut self) -> usize
354 where
355 T: Float + FromPrimitive + ToPrimitive,
356 {
357 let notes = self.get_notes();
358
359 let feature_id = self.store_mut().create_feature(2, notes.to_vec());
361
362 let tonic = self.driver().headspace().root();
364 self.tonic_history.push(tonic);
365
366 feature_id
367 }
368 pub fn set_last_context(&mut self, context: ActorContext<T>) {
370 self.last_context = Some((context, Instant::now()));
371 }
372 pub fn set_operator_by_kind(&mut self, mode: OperatorKind)
374 where
375 T: core::iter::Sum + Float + FromPrimitive + NumAssign + ToPrimitive,
376 {
377 match mode {
378 OperatorKind::Agent => {
379 if !matches!(self.operator, Operator::Agent(_)) {
380 if let Operator::Observer(observer) = &mut self.operator {
382 let _ = observer.on_deactivate(&self.driver, &mut self.store);
383 }
384
385 let mut agent = Agent::new();
387 let _ = <Agent<T> as Actor<D, T>>::initialize(&mut agent);
388 let _ = agent.on_activate(&self.driver, &mut self.store);
389
390 self.operator = Operator::Agent(agent);
391 self.last_context = None; }
393 }
394 OperatorKind::Observer => {
395 if !matches!(self.operator, Operator::Observer(_)) {
396 if let Operator::Agent(agent) = &mut self.operator {
398 let _ = agent.on_deactivate(&self.driver, &mut self.store);
399 }
400
401 let mut observer = Observer::new();
403 let _ = <Observer<T> as Actor<D, T>>::initialize(&mut observer);
404 let _ = observer.on_activate(&self.driver, &mut self.store);
405
406 self.operator = Operator::Observer(observer);
407 self.last_context = None; }
409 }
410 }
411 }
412}
413
414impl<D, T> Default for VNode<D, T>
415where
416 D: Default + RawDriver<Triad>,
417 T: Default + Float + FromPrimitive,
418{
419 fn default() -> Self {
420 Self::new()
421 }
422}
423
424impl<D, T> Eq for VNode<D, T>
425where
426 D: RawDriver<Triad>,
427 T: PartialEq,
428{
429}
430
431impl<D, T> PartialEq<VNode<D, T>> for VNode<D, T>
432where
433 D: RawDriver<Triad>,
434 Operator<T>: PartialEq,
435{
436 fn eq(&self, other: &VNode<D, T>) -> bool {
437 self.driver().headspace() == other.driver().headspace()
438 && self.operator() == other.operator()
439 && self.critical_points() == other.critical_points()
440 && self.tonic_history() == other.tonic_history()
441 }
442}
443
444impl<D, T> PartialEq<VNode<D, T>> for &VNode<D, T>
445where
446 D: RawDriver<Triad>,
447 Operator<T>: PartialEq,
448{
449 fn eq(&self, other: &VNode<D, T>) -> bool {
450 self.driver().headspace() == other.driver().headspace()
451 && self.operator() == other.operator()
452 && self.critical_points() == other.critical_points()
453 && self.tonic_history() == other.tonic_history()
454 }
455}
456
457impl<D, T> PartialEq<VNode<D, T>> for &mut VNode<D, T>
458where
459 D: RawDriver<Triad>,
460 Operator<T>: PartialEq,
461{
462 fn eq(&self, other: &VNode<D, T>) -> bool {
463 self.driver().headspace() == other.driver().headspace()
464 && self.operator() == other.operator()
465 && self.critical_points() == other.critical_points()
466 && self.tonic_history() == other.tonic_history()
467 }
468}
469
470impl<'a, D, T> PartialEq<&'a VNode<D, T>> for VNode<D, T>
471where
472 D: RawDriver<Triad>,
473 Operator<T>: PartialEq,
474{
475 fn eq(&self, other: &&'a VNode<D, T>) -> bool {
476 self.driver().headspace() == other.driver().headspace()
477 && self.operator() == other.operator()
478 && self.critical_points() == other.critical_points()
479 && self.tonic_history() == other.tonic_history()
480 }
481}
482
483impl<'a, D, T> PartialEq<&'a mut VNode<D, T>> for VNode<D, T>
484where
485 D: RawDriver<Triad>,
486 Operator<T>: PartialEq,
487{
488 fn eq(&self, other: &&'a mut VNode<D, T>) -> bool {
489 self.driver().headspace() == other.driver().headspace()
490 && self.operator() == other.operator()
491 && self.critical_points() == other.critical_points()
492 && self.tonic_history() == other.tonic_history()
493 }
494}
495
496impl<D, T> core::hash::Hash for VNode<D, T>
497where
498 D: RawDriver<Triad>,
499 Operator<T>: core::hash::Hash,
500{
501 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
502 self.driver().headspace().hash(state);
503 self.operator().hash(state);
504 }
505}