1use super::{ComputationalEngine, Engine, RawEngine};
6use crate::types::{Rulespace, Snapshot};
7
8use eryon::traits::Symbolic;
9use eryon::{Direction, Head, RawState, State, Tail};
10
11#[derive(Clone, Debug, Default, PartialEq)]
14pub struct WolframUTM<Q = usize, A = usize>
15where
16 Q: RawState + Eq + core::hash::Hash,
17 A: Symbolic,
18{
19 pub(crate) alphabet: [A; 3],
20 pub(crate) execution_history: Vec<(Head<Q, A>, Tail<Q, A>)>,
21 pub(crate) position: usize,
22 pub(crate) ruleset: Rulespace<Q, A>,
23 pub(crate) state: State<Q>,
24 pub(crate) tape: Vec<A>,
25}
26
27impl<Q, A> WolframUTM<Q, A>
28where
29 Q: RawState + Eq + core::hash::Hash,
30 A: Symbolic,
31{
32 pub const STATES: usize = 2;
33 pub const SYMBOLS: usize = 3;
34 pub fn new(alphabet: [A; 3], State(state): State<Q>) -> Self {
36 WolframUTM {
37 alphabet,
38 execution_history: Vec::new(),
39 position: 0,
40 state: State(state),
41 tape: Vec::new(),
42 ruleset: Rulespace::new(),
43 }
44 }
45 pub fn from_alphabet(alphabet: [A; 3]) -> Self
47 where
48 Q: Default,
49 {
50 Self::new(alphabet, State::default())
51 }
52 pub const fn alphabet(&self) -> &[A; 3] {
54 &self.alphabet
55 }
56 #[inline]
58 pub fn position(&self) -> usize {
59 self.position
60 }
61 pub const fn ruleset(&self) -> &Rulespace<Q, A> {
63 &self.ruleset
64 }
65 pub fn ruleset_mut(&mut self) -> &mut Rulespace<Q, A> {
67 &mut self.ruleset
68 }
69 #[inline]
71 pub fn state(&self) -> State<&Q> {
72 self.state.view()
73 }
74 pub fn state_mut(&mut self) -> State<&mut Q> {
76 self.state.view_mut()
77 }
78 pub const fn tape(&self) -> &Vec<A> {
80 &self.tape
81 }
82 pub fn tape_mut(&mut self) -> &mut Vec<A> {
84 &mut self.tape
85 }
86 pub fn head(&self) -> Head<&Q, &A> {
88 Head::new(self.state(), &self.tape[self.position])
90 }
91 pub fn contains(&self, symbol: &A) -> bool {
93 self.alphabet.contains(symbol)
94 }
95 pub fn get_current_symbol(&self) -> Option<&A> {
97 self.tape.get(self.position)
98 }
99 pub fn get_tail(&self) -> Option<&Tail<Q, A>>
101 where
102 Q: Clone,
103 {
104 self.ruleset.get(&self.head().cloned())
105 }
106 pub fn get_tail_for(&self, head: Head<Q, A>) -> &Tail<Q, A> {
108 &self.ruleset[&head]
109 }
110 pub fn set_alphabet(&mut self, alphabet: [A; 3]) {
112 self.alphabet = alphabet;
113 }
114 pub fn set_position(&mut self, position: usize) -> &mut Self {
116 self.position = position;
117 self
118 }
119 pub fn set_ruleset(&mut self, ruleset: Rulespace<Q, A>) -> &mut Self {
121 self.ruleset = ruleset;
122 self
123 }
124 pub fn set_state(&mut self, State(state): State<Q>) -> &mut Self {
126 self.state = State(state);
127 self
128 }
129 pub fn set_tape(&mut self, tape: Vec<A>) -> &mut Self {
131 self.tape = tape;
132 self
133 }
134 pub fn with_alphabet(self, alphabet: [A; 3]) -> Self {
136 Self { alphabet, ..self }
137 }
138 pub fn with_ruleset(self, ruleset: Rulespace<Q, A>) -> Self {
140 Self { ruleset, ..self }
141 }
142 pub fn with_state(self, State(state): State<Q>) -> Self {
144 Self {
145 state: State(state),
146 ..self
147 }
148 }
149 pub fn with_tape(self, tape: Vec<A>) -> Self {
151 Self {
152 position: 0,
153 tape,
154 ..self
155 }
156 }
157 pub fn reset_position(&mut self) -> &mut Self {
159 self.set_position(0);
160 self
161 }
162 pub fn reset_with_tape(&mut self, tape: Vec<A>) -> &mut Self {
164 self.set_tape(tape).reset_position()
165 }
166 pub fn run(&mut self, input: Vec<A>) -> crate::Result<Vec<Snapshot<Q, [A; 3], Vec<A>>>>
168 where
169 Q: Clone,
170 {
171 self.run_for(input, usize::MAX)
172 }
173 #[cfg_attr(
175 feature = "tracing",
176 tracing::instrument(
177 fields(max),
178 skip(self, input),
179 level = "trace",
180 name = "run_for",
181 target = "utm"
182 )
183 )]
184 pub fn run_for(
185 &mut self,
186 input: Vec<A>,
187 max: usize,
188 ) -> crate::Result<Vec<Snapshot<Q, [A; 3], Vec<A>>>>
189 where
190 Q: Clone,
191 {
192 self.reset_with_tape(input);
194
195 let mut history = vec![self.snapshot().cloned()];
196
197 let mut halt = false;
199 while self.step().is_ok() && !halt {
200 history.push(self.snapshot().cloned());
202 if history.len() > max {
204 halt = true;
205 #[cfg(feature = "tracing")]
206 tracing::warn!(
207 "Infinite loop detected; check the system and it's ruleset to ensure convergence within {} steps",
208 max
209 )
210 }
211 }
212
213 Ok(history)
214 }
215
216 pub fn step(&mut self) -> crate::Result<()>
218 where
219 Q: Clone,
220 {
221 let symbol = self.get_current_symbol().cloned().unwrap_or_default();
222
223 if !self.contains(&symbol) {
225 panic!("symbol {} not in any accessible triad context", symbol);
226 }
227 let head = Head::new(self.state.clone(), symbol);
228 self.handle(&head)
230 }
231
232 pub fn write(&mut self, symbol: A) {
233 self.tape[self.position] = symbol;
234 }
235 #[cfg_attr(
237 feature = "tracing",
238 tracing::instrument(
239 skip(self, head),
240 level = "trace",
241 name = "handle",
242 target = "wolfram"
243 )
244 )]
245 fn handle(&mut self, head: &Head<Q, A>) -> crate::Result<()>
246 where
247 Q: Clone,
248 {
249 if let Some(tail) = self.ruleset.get(head) {
250 let Tail {
251 state: new_state,
252 symbol: new_symbol,
253 direction,
254 } = tail.clone();
255 if self.position >= self.tape.len() {
257 self.tape.resize(self.position + 1, A::default());
258 }
259 self.tape[self.position] = new_symbol;
260
261 self.state = new_state;
263
264 match direction {
266 Direction::Left => {
267 if self.position > 0 {
268 self.position -= 1;
269 } else {
270 self.tape.insert(0, A::default());
271 }
272 }
273 Direction::Right => {
274 self.position += 1;
275 if self.position >= self.tape.len() {
276 self.tape.push(A::default());
277 }
278 }
279 Direction::Stay => {}
280 }
281 return Ok(());
282 }
283 Err(crate::ActorError::DriverError(
284 "No rule found for the current head...".to_string(),
285 )) }
287}
288
289use crate::mem::TopoLedger;
290
291impl WolframUTM {
292 pub fn pretty_print(&self) -> String {
294 let mut result = String::new();
295 result.push_str(&format!(
297 "(State: {:?}, Alphabet: {:?})",
298 self.state, self.alphabet
299 ));
300 for (i, &symbol) in self.tape.iter().enumerate() {
302 if i == self.position {
303 result.push_str(&format!("[{}]", symbol));
304 } else {
305 result.push_str(&format!(" {} ", symbol));
306 }
307 }
308 result
310 }
311 pub fn update_rule(&mut self, head: Head<usize, usize>, tail: Tail<usize, usize>) {
313 let entry = self.ruleset.entry(head).or_default();
315 *entry = tail;
316 }
317
318 pub fn learn_from_execution(&mut self, memory: &mut TopoLedger, steps: usize, reward: f32) {
320 if self.execution_history.len() < steps {
322 return;
323 }
324
325 let reinforcement = reward / steps as f32;
327
328 let history = self.execution_history.clone();
330 let relevant_history = history
331 .iter()
332 .rev()
333 .take(steps)
334 .collect::<Vec<_>>()
335 .into_iter()
336 .rev();
337
338 for &(head, tail) in relevant_history {
340 let Head { state, symbol } = head;
341 let Tail {
342 state: next_state,
343 symbol: next_symbol,
344 direction,
345 } = tail;
346 memory.store_learned_rule(
348 state,
349 symbol,
350 next_state,
351 next_symbol,
352 direction,
353 reinforcement,
354 );
355
356 self.update_rule(head, tail);
358 }
359 }
360}
361
362impl<Q, S> RawEngine for WolframUTM<Q, S>
363where
364 Q: RawState + Clone + Eq + core::hash::Hash,
365 S: Symbolic,
366{
367 type Store = Vec<S>;
368
369 seal!();
370}
371
372impl<Q, S> Engine for WolframUTM<Q, S>
373where
374 Q: RawState + Clone + Default + Eq + core::hash::Hash + Send + Sync,
375 S: Symbolic,
376{
377 seal!();
378}
379
380impl<Q, S> ComputationalEngine<Q, [S; 3]> for WolframUTM<Q, S>
381where
382 Q: RawState + Clone + Eq + core::hash::Hash,
383 S: Symbolic,
384{
385 fn new(alphabet: [S; 3], initial_state: State<Q>) -> Self {
386 WolframUTM::new(alphabet, initial_state)
387 }
388
389 fn alphabet(&self) -> &[S; 3] {
390 &self.alphabet
391 }
392
393 fn alphabet_mut(&mut self) -> &mut [S; 3] {
394 &mut self.alphabet
395 }
396
397 fn head(&self) -> Head<&Q, &S> {
398 self.head()
399 }
400
401 fn head_mut(&mut self) -> Head<&mut Q, &mut S> {
402 Head::new(self.state.view_mut(), &mut self.tape[self.position])
403 }
404
405 fn position(&self) -> usize {
406 self.position
407 }
408
409 fn position_mut(&mut self) -> &mut usize {
410 &mut self.position
411 }
412
413 fn state(&self) -> State<&Q> {
414 self.state.view()
415 }
416
417 fn state_mut(&mut self) -> State<&mut Q> {
418 self.state.view_mut()
419 }
420
421 fn tape(&self) -> &Vec<S> {
422 &self.tape
423 }
424
425 fn tape_mut(&mut self) -> &mut Vec<S> {
426 &mut self.tape
427 }
428
429 fn step(&mut self) -> Result<(), crate::ActorError> {
430 self.step()
431 }
432
433 fn set_alphabet(&mut self, alphabet: [S; 3]) {
434 self.alphabet = alphabet;
435 }
436
437 fn set_position(&mut self, position: usize) {
438 self.position = position;
439 }
440
441 fn set_state(&mut self, state: State<Q>) {
442 self.state = state;
443 }
444
445 fn set_tape<I>(&mut self, tape: I)
446 where
447 I: IntoIterator<Item = S>,
448 {
449 self.tape = Vec::from_iter(tape);
450 }
451}
452
453impl<Q, S> core::fmt::Display for WolframUTM<Q, S>
454where
455 Q: RawState + Eq + core::hash::Hash,
456 S: Symbolic,
457{
458 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
459 write!(
460 f,
461 "{head:?} @ {pos}: {tape:?}",
462 head = self.head(),
463 pos = self.position(),
464 tape = self.tape()
465 )
466 }
467}
468
469impl<Q, S> core::ops::Index<usize> for WolframUTM<Q, S>
470where
471 Q: RawState + Eq + core::hash::Hash,
472 S: Symbolic,
473{
474 type Output = S;
475
476 fn index(&self, index: usize) -> &Self::Output {
477 &self.tape[index]
478 }
479}
480
481impl<Q, S> core::ops::Index<Head<Q, S>> for WolframUTM<Q, S>
482where
483 Q: RawState + Eq + core::hash::Hash,
484 S: Symbolic,
485{
486 type Output = Tail<Q, S>;
487
488 fn index(&self, index: Head<Q, S>) -> &Self::Output {
489 &self.ruleset[&index]
490 }
491}