1use crate::{
3 Context,
4 compiler::RegOp,
5 context::{BadNode, Node},
6 eval::{
7 BulkEvalError, BulkEvaluator, BulkOutput, Function, MathFunction, Tape,
8 Trace, TracingEvalError, TracingEvaluator,
9 },
10 render::{RenderHints, TileSizes},
11 shape::Shape,
12 types::{FloatExt, Grad, Interval},
13 var::VarMap,
14};
15use std::sync::Arc;
16
17mod choice;
18mod data;
19
20pub use choice::Choice;
21use data::BadChoiceSlice;
22pub use data::{VmData, VmWorkspace};
23
24pub type VmFunction = GenericVmFunction<{ u8::MAX as usize }>;
34
35pub type VmShape = Shape<VmFunction>;
37
38#[derive(Default)]
40pub struct EmptyTapeStorage;
41
42#[derive(Clone)]
47pub struct GenericVmTape<const N: usize>(Arc<VmData<N>>);
48
49impl<const N: usize> GenericVmTape<N> {
50 pub fn data(&self) -> &VmData<N> {
52 &self.0
53 }
54}
55
56impl<const N: usize> Tape for GenericVmTape<N> {
57 type Storage = EmptyTapeStorage;
58 fn recycle(self) -> Option<Self::Storage> {
59 Some(EmptyTapeStorage)
60 }
61
62 fn vars(&self) -> &VarMap {
63 &self.0.vars
64 }
65
66 fn output_count(&self) -> usize {
67 self.0.output_count()
68 }
69}
70
71#[derive(Clone, Default, Eq, PartialEq)]
75pub struct VmTrace(Vec<Choice>);
76
77impl VmTrace {
78 pub fn fill(&mut self, v: Choice) {
80 self.0.fill(v);
81 }
82 pub fn resize(&mut self, n: usize, v: Choice) {
84 self.0.resize(n, v);
85 }
86 pub fn as_slice(&self) -> &[Choice] {
88 self.0.as_slice()
89 }
90 pub fn as_mut_slice(&mut self) -> &mut [Choice] {
92 self.0.as_mut_slice()
93 }
94 pub fn as_mut_ptr(&mut self) -> *mut Choice {
96 self.0.as_mut_ptr()
97 }
98}
99
100impl Trace for VmTrace {
101 fn copy_from(&mut self, other: &VmTrace) {
102 self.0.resize(other.0.len(), Choice::Unknown);
103 self.0.copy_from_slice(&other.0);
104 }
105}
106
107#[cfg(any(test, feature = "eval-tests"))]
108impl From<Vec<Choice>> for VmTrace {
109 fn from(v: Vec<Choice>) -> Self {
110 Self(v)
111 }
112}
113
114#[cfg(any(test, feature = "eval-tests"))]
115impl AsRef<[Choice]> for VmTrace {
116 fn as_ref(&self) -> &[Choice] {
117 &self.0
118 }
119}
120
121#[derive(Clone)]
126pub struct GenericVmFunction<const N: usize>(Arc<VmData<N>>);
127
128impl<const N: usize> From<VmData<N>> for GenericVmFunction<N> {
129 fn from(d: VmData<N>) -> Self {
130 Self(d.into())
131 }
132}
133
134impl<const N: usize> GenericVmFunction<N> {
135 pub fn size(&self) -> usize {
137 self.0.len()
138 }
139
140 pub fn recycle(self) -> Option<VmData<N>> {
142 Arc::try_unwrap(self.0).ok()
143 }
144
145 pub fn data(&self) -> &VmData<N> {
147 self.0.as_ref()
148 }
149
150 pub fn tape(&self) -> GenericVmTape<N> {
152 GenericVmTape(self.0.clone())
153 }
154
155 pub fn choice_count(&self) -> usize {
157 self.0.choice_count()
158 }
159
160 pub fn output_count(&self) -> usize {
162 self.0.output_count()
163 }
164
165 pub fn simplify_with<const M: usize>(
167 &self,
168 trace: &VmTrace,
169 storage: VmData<M>,
170 workspace: &mut VmWorkspace<M>,
171 ) -> Result<GenericVmFunction<M>, BadTrace> {
172 let d = self.0.simplify::<M>(trace.as_slice(), workspace, storage)?;
173 Ok(GenericVmFunction(Arc::new(d)))
174 }
175}
176
177#[derive(thiserror::Error, Debug)]
179#[error(transparent)]
180pub struct BadTrace(#[from] pub BadChoiceSlice);
181
182impl<const N: usize> Function for GenericVmFunction<N> {
183 type Storage = VmData<N>;
184 type Workspace = VmWorkspace<N>;
185
186 type TapeStorage = EmptyTapeStorage;
187
188 type FloatSliceEval = VmFloatSliceEval<N>;
189 type GradSliceEval = VmGradSliceEval<N>;
190 type PointEval = VmPointEval<N>;
191 type IntervalEval = VmIntervalEval<N>;
192 type Trace = VmTrace;
193
194 #[inline]
195 fn float_slice_tape(&self, _storage: EmptyTapeStorage) -> GenericVmTape<N> {
196 self.tape()
197 }
198
199 #[inline]
200 fn grad_slice_tape(&self, _storage: EmptyTapeStorage) -> GenericVmTape<N> {
201 self.tape()
202 }
203
204 #[inline]
205 fn point_tape(&self, _storage: EmptyTapeStorage) -> GenericVmTape<N> {
206 self.tape()
207 }
208
209 #[inline]
210 fn interval_tape(&self, _storage: EmptyTapeStorage) -> GenericVmTape<N> {
211 self.tape()
212 }
213
214 #[inline]
215 fn simplify(
216 &self,
217 trace: &Self::Trace,
218 storage: Self::Storage,
219 workspace: &mut Self::Workspace,
220 ) -> Result<Self, BadTrace> {
221 self.simplify_with(trace, storage, workspace)
222 }
223
224 #[inline]
225 fn recycle(self) -> Option<Self::Storage> {
226 GenericVmFunction::recycle(self)
227 }
228
229 #[inline]
230 fn size(&self) -> usize {
231 GenericVmFunction::size(self)
232 }
233
234 #[inline]
235 fn vars(&self) -> &VarMap {
236 &self.0.vars
237 }
238
239 #[inline]
240 fn can_simplify(&self) -> bool {
241 self.0.choice_count() > 0
242 }
243
244 #[inline]
245 fn output_count(&self) -> usize {
246 self.0.output_count()
247 }
248}
249
250impl<const N: usize> RenderHints for GenericVmFunction<N> {
251 fn tile_sizes_3d() -> TileSizes {
252 TileSizes::new(&[128, 64, 32, 16, 8]).unwrap()
253 }
254
255 fn tile_sizes_2d() -> TileSizes {
256 TileSizes::new(&[128, 32, 8]).unwrap()
257 }
258}
259
260impl<const N: usize> MathFunction for GenericVmFunction<N> {
261 fn new(ctx: &Context, nodes: &[Node]) -> Result<Self, BadNode> {
262 let d = VmData::new(ctx, nodes)?;
263 Ok(Self(d.into()))
264 }
265}
266
267struct SlotArray<'a, T>(&'a mut [T]);
271impl<T> std::ops::Index<u8> for SlotArray<'_, T> {
272 type Output = T;
273 fn index(&self, i: u8) -> &Self::Output {
274 &self.0[i as usize]
275 }
276}
277impl<T> std::ops::IndexMut<u8> for SlotArray<'_, T> {
278 fn index_mut(&mut self, i: u8) -> &mut T {
279 &mut self.0[i as usize]
280 }
281}
282impl<T> std::ops::Index<u32> for SlotArray<'_, T> {
283 type Output = T;
284 fn index(&self, i: u32) -> &Self::Output {
285 &self.0[i as usize]
286 }
287}
288impl<T> std::ops::IndexMut<u32> for SlotArray<'_, T> {
289 fn index_mut(&mut self, i: u32) -> &mut T {
290 &mut self.0[i as usize]
291 }
292}
293
294struct TracingVmEval<T> {
298 slots: Vec<T>,
299 out: Vec<T>,
300 choices: VmTrace,
301}
302
303impl<T> Default for TracingVmEval<T> {
304 fn default() -> Self {
305 Self {
306 slots: Vec::default(),
307 out: Vec::default(),
308 choices: VmTrace::default(),
309 }
310 }
311}
312
313impl<T: From<f32> + Clone> TracingVmEval<T> {
314 fn resize_slots<const N: usize>(&mut self, tape: &VmData<N>) {
315 self.slots.resize(tape.slot_count(), f32::NAN.into());
316 self.choices.resize(tape.choice_count(), Choice::Unknown);
317 self.out.resize(tape.output_count(), f32::NAN.into());
318 self.choices.fill(Choice::Unknown);
319 }
320}
321
322#[derive(Default)]
324pub struct VmIntervalEval<const N: usize>(TracingVmEval<Interval>);
325impl<const N: usize> TracingEvaluator for VmIntervalEval<N> {
326 type Data = Interval;
327 type Tape = GenericVmTape<N>;
328 type Trace = VmTrace;
329 type TapeStorage = EmptyTapeStorage;
330
331 #[inline]
332 fn eval(
333 &mut self,
334 tape: &Self::Tape,
335 vars: &[Interval],
336 ) -> Result<(&[Interval], Option<&VmTrace>), TracingEvalError> {
337 tape.vars().check_tracing_arguments(vars)?;
338 let tape = tape.data();
339 self.0.resize_slots(tape);
340
341 let mut simplify = false;
342 let mut v = SlotArray(&mut self.0.slots);
343 let mut choices = self.0.choices.as_mut_slice().iter_mut();
344 for op in tape.iter_asm() {
345 match op {
346 RegOp::Output(arg, i) => {
347 self.0.out[i as usize] = v[arg];
348 }
349 RegOp::Input(out, i) => {
350 v[out] = vars[i as usize];
351 }
352 RegOp::NegReg(out, arg) => {
353 v[out] = -v[arg];
354 }
355 RegOp::AbsReg(out, arg) => {
356 v[out] = v[arg].abs();
357 }
358 RegOp::RecipReg(out, arg) => {
359 v[out] = v[arg].recip();
360 }
361 RegOp::SqrtReg(out, arg) => {
362 v[out] = v[arg].sqrt();
363 }
364 RegOp::SquareReg(out, arg) => {
365 v[out] = v[arg].square();
366 }
367 RegOp::FloorReg(out, arg) => {
368 v[out] = v[arg].floor();
369 }
370 RegOp::CeilReg(out, arg) => {
371 v[out] = v[arg].ceil();
372 }
373 RegOp::RoundReg(out, arg) => {
374 v[out] = v[arg].round();
375 }
376 RegOp::SinReg(out, arg) => {
377 v[out] = v[arg].sin();
378 }
379 RegOp::CosReg(out, arg) => {
380 v[out] = v[arg].cos();
381 }
382 RegOp::TanReg(out, arg) => {
383 v[out] = v[arg].tan();
384 }
385 RegOp::AsinReg(out, arg) => {
386 v[out] = v[arg].asin();
387 }
388 RegOp::AcosReg(out, arg) => {
389 v[out] = v[arg].acos();
390 }
391 RegOp::AtanReg(out, arg) => {
392 v[out] = v[arg].atan();
393 }
394 RegOp::ExpReg(out, arg) => {
395 v[out] = v[arg].exp();
396 }
397 RegOp::LnReg(out, arg) => {
398 v[out] = v[arg].ln();
399 }
400 RegOp::NotReg(out, arg) => {
401 v[out] = v[arg].not();
402 }
403 RegOp::RandReg(out, arg) => {
404 v[out] = v[arg].rand();
405 }
406 RegOp::CopyReg(out, arg) => v[out] = v[arg],
407 RegOp::AddRegImm(out, arg, imm) => {
408 v[out] = v[arg] + imm.into();
409 }
410 RegOp::MulRegImm(out, arg, imm) => {
411 v[out] = v[arg] * imm;
412 }
413 RegOp::DivRegImm(out, arg, imm) => {
414 v[out] = v[arg] / imm.into();
415 }
416 RegOp::DivImmReg(out, arg, imm) => {
417 let imm: Interval = imm.into();
418 v[out] = imm / v[arg];
419 }
420 RegOp::AtanRegImm(out, arg, imm) => {
421 v[out] = v[arg].atan2(imm.into());
422 }
423 RegOp::AtanImmReg(out, arg, imm) => {
424 let imm: Interval = imm.into();
425 v[out] = imm.atan2(v[arg]);
426 }
427 RegOp::AtanRegReg(out, lhs, rhs) => {
428 v[out] = v[lhs].atan2(v[rhs]);
429 }
430 RegOp::SubImmReg(out, arg, imm) => {
431 v[out] = Interval::from(imm) - v[arg];
432 }
433 RegOp::SubRegImm(out, arg, imm) => {
434 v[out] = v[arg] - imm.into();
435 }
436 RegOp::MinRegImm(out, arg, imm) => {
437 let (value, choice) = v[arg].min_choice(imm.into());
438 v[out] = value;
439 *choices.next().unwrap() |= choice;
440 simplify |= choice != Choice::Both;
441 }
442 RegOp::MaxRegImm(out, arg, imm) => {
443 let (value, choice) = v[arg].max_choice(imm.into());
444 v[out] = value;
445 *choices.next().unwrap() |= choice;
446 simplify |= choice != Choice::Both;
447 }
448 RegOp::AndRegReg(out, lhs, rhs) => {
449 let (value, choice) = v[lhs].and_choice(v[rhs]);
450 v[out] = value;
451 *choices.next().unwrap() |= choice;
452 simplify |= choice != Choice::Both;
453 }
454 RegOp::AndRegImm(out, arg, imm) => {
455 let (value, choice) = v[arg].and_choice(imm.into());
456 v[out] = value;
457 *choices.next().unwrap() |= choice;
458 simplify |= choice != Choice::Both;
459 }
460 RegOp::OrRegReg(out, lhs, rhs) => {
461 let (value, choice) = v[lhs].or_choice(v[rhs]);
462 v[out] = value;
463 *choices.next().unwrap() |= choice;
464 simplify |= choice != Choice::Both;
465 }
466 RegOp::OrRegImm(out, arg, imm) => {
467 let (value, choice) = v[arg].or_choice(imm.into());
468 v[out] = value;
469 *choices.next().unwrap() |= choice;
470 simplify |= choice != Choice::Both;
471 }
472 RegOp::ModRegReg(out, lhs, rhs) => {
473 v[out] = v[lhs].rem_euclid(v[rhs]);
474 }
475 RegOp::ModRegImm(out, arg, imm) => {
476 v[out] = v[arg].rem_euclid(imm.into());
477 }
478 RegOp::ModImmReg(out, arg, imm) => {
479 v[out] = Interval::from(imm).rem_euclid(v[arg]);
480 }
481 RegOp::AddRegReg(out, lhs, rhs) => v[out] = v[lhs] + v[rhs],
482 RegOp::MulRegReg(out, lhs, rhs) => v[out] = v[lhs] * v[rhs],
483 RegOp::DivRegReg(out, lhs, rhs) => v[out] = v[lhs] / v[rhs],
484 RegOp::SubRegReg(out, lhs, rhs) => v[out] = v[lhs] - v[rhs],
485 RegOp::CompareRegReg(out, lhs, rhs) => {
486 v[out] = Interval::compare(v[lhs], v[rhs]);
487 }
488 RegOp::CompareRegImm(out, arg, imm) => {
489 v[out] = Interval::compare(v[arg], imm);
490 }
491 RegOp::CompareImmReg(out, arg, imm) => {
492 v[out] = Interval::compare(imm, v[arg]);
493 }
494 RegOp::MixRegReg(out, lhs, rhs) => {
495 v[out] = v[lhs].mix(v[rhs]);
496 }
497 RegOp::MixRegImm(out, arg, imm) => {
498 v[out] = v[arg].mix(imm.into());
499 }
500 RegOp::MixImmReg(out, arg, imm) => {
501 v[out] = Interval::from(imm).mix(v[arg]);
502 }
503
504 RegOp::MinRegReg(out, lhs, rhs) => {
505 let (value, choice) = v[lhs].min_choice(v[rhs]);
506 v[out] = value;
507 *choices.next().unwrap() |= choice;
508 simplify |= choice != Choice::Both;
509 }
510 RegOp::MaxRegReg(out, lhs, rhs) => {
511 let (value, choice) = v[lhs].max_choice(v[rhs]);
512 v[out] = value;
513 *choices.next().unwrap() |= choice;
514 simplify |= choice != Choice::Both;
515 }
516 RegOp::CopyImm(out, imm) => {
517 v[out] = imm.into();
518 }
519 RegOp::Load(out, mem) => {
520 v[out] = v[mem];
521 }
522 RegOp::Store(out, mem) => {
523 v[mem] = v[out];
524 }
525 }
526 }
527 Ok((
528 &self.0.out,
529 if simplify {
530 Some(&self.0.choices)
531 } else {
532 None
533 },
534 ))
535 }
536}
537
538#[derive(Default)]
540pub struct VmPointEval<const N: usize>(TracingVmEval<f32>);
541impl<const N: usize> TracingEvaluator for VmPointEval<N> {
542 type Data = f32;
543 type Tape = GenericVmTape<N>;
544 type Trace = VmTrace;
545 type TapeStorage = EmptyTapeStorage;
546
547 #[inline]
548 fn eval(
549 &mut self,
550 tape: &Self::Tape,
551 vars: &[f32],
552 ) -> Result<(&[f32], Option<&VmTrace>), TracingEvalError> {
553 tape.vars().check_tracing_arguments(vars)?;
554 let tape = tape.data();
555 self.0.resize_slots(tape);
556
557 let mut choices = self.0.choices.as_mut_slice().iter_mut();
558 let mut simplify = false;
559 let mut v = SlotArray(&mut self.0.slots);
560 for op in tape.iter_asm() {
561 match op {
562 RegOp::Output(arg, i) => {
563 self.0.out[i as usize] = v[arg];
564 }
565 RegOp::Input(out, i) => {
566 v[out] = vars[i as usize];
567 }
568 RegOp::NegReg(out, arg) => {
569 v[out] = -v[arg];
570 }
571 RegOp::AbsReg(out, arg) => {
572 v[out] = v[arg].abs();
573 }
574 RegOp::RecipReg(out, arg) => {
575 v[out] = 1.0 / v[arg];
576 }
577 RegOp::SqrtReg(out, arg) => {
578 v[out] = v[arg].sqrt();
579 }
580 RegOp::SquareReg(out, arg) => {
581 let s = v[arg];
582 v[out] = s * s;
583 }
584 RegOp::FloorReg(out, arg) => {
585 v[out] = v[arg].floor();
586 }
587 RegOp::CeilReg(out, arg) => {
588 v[out] = v[arg].ceil();
589 }
590 RegOp::RoundReg(out, arg) => {
591 v[out] = v[arg].round();
592 }
593 RegOp::SinReg(out, arg) => {
594 v[out] = v[arg].sin();
595 }
596 RegOp::CosReg(out, arg) => {
597 v[out] = v[arg].cos();
598 }
599 RegOp::TanReg(out, arg) => {
600 v[out] = v[arg].tan();
601 }
602 RegOp::AsinReg(out, arg) => {
603 v[out] = v[arg].asin();
604 }
605 RegOp::AcosReg(out, arg) => {
606 v[out] = v[arg].acos();
607 }
608 RegOp::AtanReg(out, arg) => {
609 v[out] = v[arg].atan();
610 }
611 RegOp::ExpReg(out, arg) => {
612 v[out] = v[arg].exp();
613 }
614 RegOp::LnReg(out, arg) => {
615 v[out] = v[arg].ln();
616 }
617 RegOp::NotReg(out, arg) => v[out] = (v[arg] == 0.0).into(),
618 RegOp::RandReg(out, arg) => {
619 v[out] = v[arg].rand();
620 }
621 RegOp::CopyReg(out, arg) => {
622 v[out] = v[arg];
623 }
624 RegOp::AddRegImm(out, arg, imm) => {
625 v[out] = v[arg] + imm;
626 }
627 RegOp::MulRegImm(out, arg, imm) => {
628 v[out] = v[arg] * imm;
629 }
630 RegOp::DivRegImm(out, arg, imm) => {
631 v[out] = v[arg] / imm;
632 }
633 RegOp::DivImmReg(out, arg, imm) => {
634 v[out] = imm / v[arg];
635 }
636 RegOp::AtanRegImm(out, arg, imm) => {
637 v[out] = v[arg].atan2(imm);
638 }
639 RegOp::AtanImmReg(out, arg, imm) => {
640 v[out] = imm.atan2(v[arg]);
641 }
642 RegOp::AtanRegReg(out, lhs, rhs) => {
643 v[out] = v[lhs].atan2(v[rhs]);
644 }
645 RegOp::SubImmReg(out, arg, imm) => {
646 v[out] = imm - v[arg];
647 }
648 RegOp::SubRegImm(out, arg, imm) => {
649 v[out] = v[arg] - imm;
650 }
651 RegOp::MinRegImm(out, arg, imm) => {
652 let (value, choice) = v[arg].min_choice(imm);
653 v[out] = value;
654 *choices.next().unwrap() |= choice;
655 simplify |= choice != Choice::Both;
656 }
657 RegOp::MaxRegImm(out, arg, imm) => {
658 let (value, choice) = v[arg].max_choice(imm);
659 v[out] = value;
660 *choices.next().unwrap() |= choice;
661 simplify |= choice != Choice::Both;
662 }
663 RegOp::AndRegImm(out, arg, imm) => {
664 let (value, choice) = v[arg].and_choice(imm);
665 v[out] = value;
666 *choices.next().unwrap() |= choice;
667 simplify |= choice != Choice::Both;
668 }
669 RegOp::OrRegImm(out, arg, imm) => {
670 let (value, choice) = v[arg].or_choice(imm);
671 v[out] = value;
672 *choices.next().unwrap() |= choice;
673 simplify |= choice != Choice::Both;
674 }
675 RegOp::ModRegReg(out, lhs, rhs) => {
676 v[out] = v[lhs].rem_euclid(v[rhs]);
677 }
678 RegOp::ModRegImm(out, arg, imm) => {
679 v[out] = v[arg].rem_euclid(imm);
680 }
681 RegOp::ModImmReg(out, arg, imm) => {
682 v[out] = imm.rem_euclid(v[arg]);
683 }
684 RegOp::AddRegReg(out, lhs, rhs) => {
685 v[out] = v[lhs] + v[rhs];
686 }
687 RegOp::MulRegReg(out, lhs, rhs) => {
688 v[out] = v[lhs] * v[rhs];
689 }
690 RegOp::DivRegReg(out, lhs, rhs) => {
691 v[out] = v[lhs] / v[rhs];
692 }
693 RegOp::CompareRegReg(out, lhs, rhs) => {
694 v[out] = v[lhs].compare(v[rhs]);
695 }
696 RegOp::CompareRegImm(out, arg, imm) => {
697 v[out] = v[arg].compare(imm);
698 }
699 RegOp::CompareImmReg(out, arg, imm) => {
700 v[out] = imm.compare(v[arg]);
701 }
702 RegOp::MixRegReg(out, lhs, rhs) => {
703 v[out] = v[lhs].mix(v[rhs]);
704 }
705 RegOp::MixRegImm(out, arg, imm) => {
706 v[out] = v[arg].mix(imm);
707 }
708 RegOp::MixImmReg(out, arg, imm) => {
709 v[out] = imm.mix(v[arg]);
710 }
711 RegOp::SubRegReg(out, lhs, rhs) => {
712 v[out] = v[lhs] - v[rhs];
713 }
714 RegOp::MinRegReg(out, lhs, rhs) => {
715 let (value, choice) = v[lhs].min_choice(v[rhs]);
716 v[out] = value;
717 *choices.next().unwrap() |= choice;
718 simplify |= choice != Choice::Both;
719 }
720 RegOp::MaxRegReg(out, lhs, rhs) => {
721 let (value, choice) = v[lhs].max_choice(v[rhs]);
722 v[out] = value;
723 *choices.next().unwrap() |= choice;
724 simplify |= choice != Choice::Both;
725 }
726 RegOp::AndRegReg(out, lhs, rhs) => {
727 let (value, choice) = v[lhs].and_choice(v[rhs]);
728 v[out] = value;
729 *choices.next().unwrap() |= choice;
730 simplify |= choice != Choice::Both;
731 }
732 RegOp::OrRegReg(out, lhs, rhs) => {
733 let (value, choice) = v[lhs].or_choice(v[rhs]);
734 v[out] = value;
735 *choices.next().unwrap() |= choice;
736 simplify |= choice != Choice::Both;
737 }
738 RegOp::CopyImm(out, imm) => {
739 v[out] = imm;
740 }
741 RegOp::Load(out, mem) => {
742 v[out] = v[mem];
743 }
744 RegOp::Store(out, mem) => {
745 v[mem] = v[out];
746 }
747 }
748 }
749 Ok((
750 &self.0.out,
751 if simplify {
752 Some(&self.0.choices)
753 } else {
754 None
755 },
756 ))
757 }
758}
759
760#[derive(Default)]
764struct BulkVmEval<T> {
765 slots: Vec<Vec<T>>,
767
768 out: Vec<Vec<T>>,
770}
771
772impl<T: From<f32> + Clone> BulkVmEval<T> {
773 fn resize_slots<const N: usize>(&mut self, tape: &VmData<N>, size: usize) {
775 self.slots
776 .resize_with(tape.slot_count(), || vec![f32::NAN.into(); size]);
777 for s in self.slots.iter_mut() {
778 s.resize(size, f32::NAN.into());
779 }
780
781 self.out
782 .resize_with(tape.output_count(), || vec![f32::NAN.into(); size]);
783 for o in self.out.iter_mut() {
784 o.resize(size, f32::NAN.into());
785 }
786 }
787}
788
789#[derive(Default)]
791pub struct VmFloatSliceEval<const N: usize>(BulkVmEval<f32>);
792impl<const N: usize> BulkEvaluator for VmFloatSliceEval<N> {
793 type Data = f32;
794 type Tape = GenericVmTape<N>;
795 type TapeStorage = EmptyTapeStorage;
796
797 #[inline]
798 fn eval<V: std::ops::Deref<Target = [Self::Data]>>(
799 &mut self,
800 tape: &Self::Tape,
801 vars: &[V],
802 ) -> Result<BulkOutput<'_, f32>, BulkEvalError> {
803 tape.vars().check_bulk_arguments(vars)?;
804 let tape = tape.data();
805
806 let size = vars.first().map(|v| v.len()).unwrap_or(0);
807 self.0.resize_slots(tape, size);
808
809 let mut v = SlotArray(&mut self.0.slots);
810 for op in tape.iter_asm() {
811 match op {
812 RegOp::Output(arg, i) => {
813 self.0.out[i as usize][0..size]
814 .copy_from_slice(&v[arg][0..size]);
815 }
816 RegOp::Input(out, i) => {
817 v[out][0..size].copy_from_slice(&vars[i as usize]);
818 }
819 RegOp::NegReg(out, arg) => {
820 for i in 0..size {
821 v[out][i] = -v[arg][i];
822 }
823 }
824 RegOp::AbsReg(out, arg) => {
825 for i in 0..size {
826 v[out][i] = v[arg][i].abs();
827 }
828 }
829 RegOp::RecipReg(out, arg) => {
830 for i in 0..size {
831 v[out][i] = 1.0 / v[arg][i];
832 }
833 }
834 RegOp::SqrtReg(out, arg) => {
835 for i in 0..size {
836 v[out][i] = v[arg][i].sqrt();
837 }
838 }
839 RegOp::SquareReg(out, arg) => {
840 for i in 0..size {
841 let s = v[arg][i];
842 v[out][i] = s * s;
843 }
844 }
845 RegOp::FloorReg(out, arg) => {
846 for i in 0..size {
847 v[out][i] = v[arg][i].floor();
848 }
849 }
850 RegOp::CeilReg(out, arg) => {
851 for i in 0..size {
852 v[out][i] = v[arg][i].ceil();
853 }
854 }
855 RegOp::RoundReg(out, arg) => {
856 for i in 0..size {
857 v[out][i] = v[arg][i].round();
858 }
859 }
860 RegOp::SinReg(out, arg) => {
861 for i in 0..size {
862 v[out][i] = v[arg][i].sin();
863 }
864 }
865 RegOp::CosReg(out, arg) => {
866 for i in 0..size {
867 v[out][i] = v[arg][i].cos();
868 }
869 }
870 RegOp::TanReg(out, arg) => {
871 for i in 0..size {
872 v[out][i] = v[arg][i].tan();
873 }
874 }
875 RegOp::AsinReg(out, arg) => {
876 for i in 0..size {
877 v[out][i] = v[arg][i].asin();
878 }
879 }
880 RegOp::AcosReg(out, arg) => {
881 for i in 0..size {
882 v[out][i] = v[arg][i].acos();
883 }
884 }
885 RegOp::AtanReg(out, arg) => {
886 for i in 0..size {
887 v[out][i] = v[arg][i].atan();
888 }
889 }
890 RegOp::ExpReg(out, arg) => {
891 for i in 0..size {
892 v[out][i] = v[arg][i].exp();
893 }
894 }
895 RegOp::LnReg(out, arg) => {
896 for i in 0..size {
897 v[out][i] = v[arg][i].ln();
898 }
899 }
900 RegOp::NotReg(out, arg) => {
901 for i in 0..size {
902 v[out][i] = (v[arg][i] == 0.0).into();
903 }
904 }
905 RegOp::RandReg(out, arg) => {
906 for i in 0..size {
907 v[out][i] = v[arg][i].rand();
908 }
909 }
910 RegOp::CopyReg(out, arg) => {
911 for i in 0..size {
912 v[out][i] = v[arg][i];
913 }
914 }
915 RegOp::AddRegImm(out, arg, imm) => {
916 for i in 0..size {
917 v[out][i] = v[arg][i] + imm;
918 }
919 }
920 RegOp::MulRegImm(out, arg, imm) => {
921 for i in 0..size {
922 v[out][i] = v[arg][i] * imm;
923 }
924 }
925 RegOp::DivRegImm(out, arg, imm) => {
926 for i in 0..size {
927 v[out][i] = v[arg][i] / imm;
928 }
929 }
930 RegOp::DivImmReg(out, arg, imm) => {
931 for i in 0..size {
932 v[out][i] = imm / v[arg][i];
933 }
934 }
935 RegOp::AtanRegImm(out, arg, imm) => {
936 for i in 0..size {
937 v[out][i] = v[arg][i].atan2(imm);
938 }
939 }
940 RegOp::AtanImmReg(out, arg, imm) => {
941 for i in 0..size {
942 v[out][i] = imm.atan2(v[arg][i]);
943 }
944 }
945 RegOp::AtanRegReg(out, lhs, rhs) => {
946 for i in 0..size {
947 v[out][i] = v[lhs][i].atan2(v[rhs][i]);
948 }
949 }
950 RegOp::SubImmReg(out, arg, imm) => {
951 for i in 0..size {
952 v[out][i] = imm - v[arg][i];
953 }
954 }
955 RegOp::SubRegImm(out, arg, imm) => {
956 for i in 0..size {
957 v[out][i] = v[arg][i] - imm;
958 }
959 }
960 RegOp::CompareImmReg(out, arg, imm) => {
961 for i in 0..size {
962 v[out][i] = imm.compare(v[arg][i]);
963 }
964 }
965 RegOp::CompareRegImm(out, arg, imm) => {
966 for i in 0..size {
967 v[out][i] = v[arg][i].compare(imm);
968 }
969 }
970 RegOp::MixRegReg(out, lhs, rhs) => {
971 for i in 0..size {
972 v[out][i] = v[lhs][i].mix(v[rhs][i]);
973 }
974 }
975 RegOp::MixRegImm(out, arg, imm) => {
976 for i in 0..size {
977 v[out][i] = v[arg][i].mix(imm);
978 }
979 }
980 RegOp::MixImmReg(out, arg, imm) => {
981 for i in 0..size {
982 v[out][i] = imm.mix(v[arg][i]);
983 }
984 }
985 RegOp::MinRegImm(out, arg, imm) => {
986 for i in 0..size {
987 v[out][i] = v[arg][i].min_choice(imm).0;
988 }
989 }
990 RegOp::MaxRegImm(out, arg, imm) => {
991 for i in 0..size {
992 v[out][i] = v[arg][i].max_choice(imm).0;
993 }
994 }
995 RegOp::AndRegImm(out, arg, imm) => {
996 for i in 0..size {
997 v[out][i] = v[arg][i].and_choice(imm).0;
998 }
999 }
1000 RegOp::OrRegImm(out, arg, imm) => {
1001 for i in 0..size {
1002 v[out][i] = v[arg][i].or_choice(imm).0;
1003 }
1004 }
1005 RegOp::ModRegReg(out, lhs, rhs) => {
1006 for i in 0..size {
1007 v[out][i] = v[lhs][i].rem_euclid(v[rhs][i]);
1008 }
1009 }
1010 RegOp::ModRegImm(out, arg, imm) => {
1011 for i in 0..size {
1012 v[out][i] = v[arg][i].rem_euclid(imm);
1013 }
1014 }
1015 RegOp::ModImmReg(out, arg, imm) => {
1016 for i in 0..size {
1017 v[out][i] = imm.rem_euclid(v[arg][i]);
1018 }
1019 }
1020 RegOp::AddRegReg(out, lhs, rhs) => {
1021 for i in 0..size {
1022 v[out][i] = v[lhs][i] + v[rhs][i];
1023 }
1024 }
1025 RegOp::MulRegReg(out, lhs, rhs) => {
1026 for i in 0..size {
1027 v[out][i] = v[lhs][i] * v[rhs][i];
1028 }
1029 }
1030 RegOp::DivRegReg(out, lhs, rhs) => {
1031 for i in 0..size {
1032 v[out][i] = v[lhs][i] / v[rhs][i];
1033 }
1034 }
1035 RegOp::SubRegReg(out, lhs, rhs) => {
1036 for i in 0..size {
1037 v[out][i] = v[lhs][i] - v[rhs][i];
1038 }
1039 }
1040 RegOp::CompareRegReg(out, lhs, rhs) => {
1041 for i in 0..size {
1042 v[out][i] = v[lhs][i].compare(v[rhs][i]);
1043 }
1044 }
1045 RegOp::MinRegReg(out, lhs, rhs) => {
1046 for i in 0..size {
1047 v[out][i] = v[lhs][i].min_choice(v[rhs][i]).0;
1048 }
1049 }
1050 RegOp::MaxRegReg(out, lhs, rhs) => {
1051 for i in 0..size {
1052 v[out][i] = v[lhs][i].max_choice(v[rhs][i]).0;
1053 }
1054 }
1055 RegOp::AndRegReg(out, lhs, rhs) => {
1056 for i in 0..size {
1057 v[out][i] = v[lhs][i].and_choice(v[rhs][i]).0;
1058 }
1059 }
1060 RegOp::OrRegReg(out, lhs, rhs) => {
1061 for i in 0..size {
1062 v[out][i] = v[lhs][i].or_choice(v[rhs][i]).0;
1063 }
1064 }
1065 RegOp::CopyImm(out, imm) => {
1066 for i in 0..size {
1067 v[out][i] = imm;
1068 }
1069 }
1070 RegOp::Load(out, mem) => {
1071 for i in 0..size {
1072 v[out][i] = v[mem][i];
1073 }
1074 }
1075 RegOp::Store(out, mem) => {
1076 for i in 0..size {
1077 v[mem][i] = v[out][i];
1078 }
1079 }
1080 }
1081 }
1082 Ok(BulkOutput::new(&self.0.out, size))
1083 }
1084}
1085
1086#[derive(Default)]
1088pub struct VmGradSliceEval<const N: usize>(BulkVmEval<Grad>);
1089impl<const N: usize> BulkEvaluator for VmGradSliceEval<N> {
1090 type Data = Grad;
1091 type Tape = GenericVmTape<N>;
1092 type TapeStorage = EmptyTapeStorage;
1093
1094 #[inline]
1095 fn eval<V: std::ops::Deref<Target = [Self::Data]>>(
1096 &mut self,
1097 tape: &Self::Tape,
1098 vars: &[V],
1099 ) -> Result<BulkOutput<'_, Grad>, BulkEvalError> {
1100 tape.vars().check_bulk_arguments(vars)?;
1101 let tape = tape.data();
1102 let size = vars.first().map(|v| v.len()).unwrap_or(0);
1103 self.0.resize_slots(tape, size);
1104
1105 let mut v = SlotArray(&mut self.0.slots);
1106 for op in tape.iter_asm() {
1107 match op {
1108 RegOp::Output(arg, i) => {
1109 self.0.out[i as usize][0..size]
1110 .copy_from_slice(&v[arg][0..size]);
1111 }
1112 RegOp::Input(out, i) => {
1113 v[out][0..size].copy_from_slice(&vars[i as usize]);
1114 }
1115 RegOp::NegReg(out, arg) => {
1116 for i in 0..size {
1117 v[out][i] = -v[arg][i];
1118 }
1119 }
1120 RegOp::AbsReg(out, arg) => {
1121 for i in 0..size {
1122 v[out][i] = v[arg][i].abs();
1123 }
1124 }
1125 RegOp::RecipReg(out, arg) => {
1126 let one: Grad = 1.0.into();
1127 for i in 0..size {
1128 v[out][i] = one / v[arg][i];
1129 }
1130 }
1131 RegOp::SqrtReg(out, arg) => {
1132 for i in 0..size {
1133 v[out][i] = v[arg][i].sqrt();
1134 }
1135 }
1136 RegOp::SquareReg(out, arg) => {
1137 for i in 0..size {
1138 let s = v[arg][i];
1139 v[out][i] = s * s;
1140 }
1141 }
1142 RegOp::FloorReg(out, arg) => {
1143 for i in 0..size {
1144 v[out][i] = v[arg][i].floor();
1145 }
1146 }
1147 RegOp::CeilReg(out, arg) => {
1148 for i in 0..size {
1149 v[out][i] = v[arg][i].ceil();
1150 }
1151 }
1152 RegOp::RoundReg(out, arg) => {
1153 for i in 0..size {
1154 v[out][i] = v[arg][i].round();
1155 }
1156 }
1157 RegOp::SinReg(out, arg) => {
1158 for i in 0..size {
1159 v[out][i] = v[arg][i].sin();
1160 }
1161 }
1162 RegOp::CosReg(out, arg) => {
1163 for i in 0..size {
1164 v[out][i] = v[arg][i].cos();
1165 }
1166 }
1167 RegOp::TanReg(out, arg) => {
1168 for i in 0..size {
1169 v[out][i] = v[arg][i].tan();
1170 }
1171 }
1172 RegOp::AsinReg(out, arg) => {
1173 for i in 0..size {
1174 v[out][i] = v[arg][i].asin();
1175 }
1176 }
1177 RegOp::AcosReg(out, arg) => {
1178 for i in 0..size {
1179 v[out][i] = v[arg][i].acos();
1180 }
1181 }
1182 RegOp::AtanReg(out, arg) => {
1183 for i in 0..size {
1184 v[out][i] = v[arg][i].atan();
1185 }
1186 }
1187 RegOp::ExpReg(out, arg) => {
1188 for i in 0..size {
1189 v[out][i] = v[arg][i].exp();
1190 }
1191 }
1192 RegOp::LnReg(out, arg) => {
1193 for i in 0..size {
1194 v[out][i] = v[arg][i].ln();
1195 }
1196 }
1197 RegOp::NotReg(out, arg) => {
1198 for i in 0..size {
1199 v[out][i] = v[arg][i].not();
1200 }
1201 }
1202 RegOp::RandReg(out, arg) => {
1203 for i in 0..size {
1204 v[out][i] = v[arg][i].rand();
1205 }
1206 }
1207 RegOp::CopyReg(out, arg) => {
1208 for i in 0..size {
1209 v[out][i] = v[arg][i];
1210 }
1211 }
1212 RegOp::AddRegImm(out, arg, imm) => {
1213 for i in 0..size {
1214 v[out][i] = v[arg][i] + imm.into();
1215 }
1216 }
1217 RegOp::MulRegImm(out, arg, imm) => {
1218 for i in 0..size {
1219 v[out][i] = v[arg][i] * imm;
1220 }
1221 }
1222 RegOp::DivRegImm(out, arg, imm) => {
1223 for i in 0..size {
1224 v[out][i] = v[arg][i] / imm.into();
1225 }
1226 }
1227 RegOp::DivImmReg(out, arg, imm) => {
1228 let imm = Grad::from(imm);
1229 for i in 0..size {
1230 v[out][i] = imm / v[arg][i];
1231 }
1232 }
1233 RegOp::AtanRegImm(out, arg, imm) => {
1234 let imm = Grad::from(imm);
1235 for i in 0..size {
1236 v[out][i] = v[arg][i].atan2(imm);
1237 }
1238 }
1239 RegOp::AtanImmReg(out, arg, imm) => {
1240 let imm = Grad::from(imm);
1241 for i in 0..size {
1242 v[out][i] = imm.atan2(v[arg][i]);
1243 }
1244 }
1245 RegOp::AtanRegReg(out, lhs, rhs) => {
1246 for i in 0..size {
1247 v[out][i] = v[lhs][i].atan2(v[rhs][i]);
1248 }
1249 }
1250 RegOp::SubImmReg(out, arg, imm) => {
1251 let imm: Grad = imm.into();
1252 for i in 0..size {
1253 v[out][i] = imm - v[arg][i];
1254 }
1255 }
1256 RegOp::SubRegImm(out, arg, imm) => {
1257 let imm: Grad = imm.into();
1258 for i in 0..size {
1259 v[out][i] = v[arg][i] - imm;
1260 }
1261 }
1262 RegOp::CompareImmReg(out, arg, imm) => {
1263 let imm: Grad = imm.into();
1264 for i in 0..size {
1265 v[out][i] = imm.compare(v[arg][i]);
1266 }
1267 }
1268 RegOp::MixRegReg(out, lhs, rhs) => {
1269 for i in 0..size {
1270 v[out][i] = v[lhs][i].mix(v[rhs][i]);
1271 }
1272 }
1273 RegOp::MixRegImm(out, arg, imm) => {
1274 let imm = imm.into();
1275 for i in 0..size {
1276 v[out][i] = v[arg][i].mix(imm);
1277 }
1278 }
1279 RegOp::MixImmReg(out, arg, imm) => {
1280 let imm = Grad::from(imm);
1281 for i in 0..size {
1282 v[out][i] = imm.mix(v[arg][i]);
1283 }
1284 }
1285 RegOp::CompareRegImm(out, arg, imm) => {
1286 let imm = imm.into();
1287 for i in 0..size {
1288 v[out][i] = v[arg][i].compare(imm);
1289 }
1290 }
1291 RegOp::MinRegImm(out, arg, imm) => {
1292 let imm: Grad = imm.into();
1293 for i in 0..size {
1294 v[out][i] = v[arg][i].min(imm);
1295 }
1296 }
1297 RegOp::MaxRegImm(out, arg, imm) => {
1298 let imm: Grad = imm.into();
1299 for i in 0..size {
1300 v[out][i] = v[arg][i].max(imm)
1301 }
1302 }
1303 RegOp::ModRegReg(out, lhs, rhs) => {
1304 for i in 0..size {
1305 v[out][i] = v[lhs][i].rem_euclid(v[rhs][i]);
1306 }
1307 }
1308 RegOp::ModRegImm(out, arg, imm) => {
1309 for i in 0..size {
1310 v[out][i] = v[arg][i].rem_euclid(imm.into());
1311 }
1312 }
1313 RegOp::ModImmReg(out, arg, imm) => {
1314 for i in 0..size {
1315 v[out][i] = Grad::from(imm).rem_euclid(v[arg][i]);
1316 }
1317 }
1318 RegOp::AddRegReg(out, lhs, rhs) => {
1319 for i in 0..size {
1320 v[out][i] = v[lhs][i] + v[rhs][i];
1321 }
1322 }
1323 RegOp::MulRegReg(out, lhs, rhs) => {
1324 for i in 0..size {
1325 v[out][i] = v[lhs][i] * v[rhs][i];
1326 }
1327 }
1328 RegOp::AndRegReg(out, lhs, rhs) => {
1329 for i in 0..size {
1330 v[out][i] = v[lhs][i].and(v[rhs][i]);
1331 }
1332 }
1333 RegOp::AndRegImm(out, arg, imm) => {
1334 let imm = imm.into();
1335 for i in 0..size {
1336 v[out][i] = v[arg][i].and(imm);
1337 }
1338 }
1339 RegOp::OrRegReg(out, lhs, rhs) => {
1340 for i in 0..size {
1341 v[out][i] = v[lhs][i].or(v[rhs][i]);
1342 }
1343 }
1344 RegOp::OrRegImm(out, arg, imm) => {
1345 let imm = imm.into();
1346 for i in 0..size {
1347 v[out][i] = v[arg][i].or(imm);
1348 }
1349 }
1350 RegOp::DivRegReg(out, lhs, rhs) => {
1351 for i in 0..size {
1352 v[out][i] = v[lhs][i] / v[rhs][i];
1353 }
1354 }
1355 RegOp::SubRegReg(out, lhs, rhs) => {
1356 for i in 0..size {
1357 v[out][i] = v[lhs][i] - v[rhs][i];
1358 }
1359 }
1360 RegOp::CompareRegReg(out, lhs, rhs) => {
1361 for i in 0..size {
1362 v[out][i] = v[lhs][i].compare(v[rhs][i]);
1363 }
1364 }
1365 RegOp::MinRegReg(out, lhs, rhs) => {
1366 for i in 0..size {
1367 v[out][i] = v[lhs][i].min(v[rhs][i]);
1368 }
1369 }
1370 RegOp::MaxRegReg(out, lhs, rhs) => {
1371 for i in 0..size {
1372 v[out][i] = v[lhs][i].max(v[rhs][i]);
1373 }
1374 }
1375 RegOp::CopyImm(out, imm) => {
1376 let imm: Grad = imm.into();
1377 for i in 0..size {
1378 v[out][i] = imm;
1379 }
1380 }
1381 RegOp::Load(out, mem) => {
1382 for i in 0..size {
1383 v[out][i] = v[mem][i];
1384 }
1385 }
1386 RegOp::Store(out, mem) => {
1387 for i in 0..size {
1388 v[mem][i] = v[out][i];
1389 }
1390 }
1391 }
1392 }
1393 Ok(BulkOutput::new(&self.0.out, size))
1394 }
1395}
1396
1397#[cfg(test)]
1398mod test {
1399 use super::*;
1400 crate::grad_slice_tests!(VmFunction);
1401 crate::interval_tests!(VmFunction);
1402 crate::float_slice_tests!(VmFunction);
1403 crate::point_tests!(VmFunction);
1404}