1use std::any::{Any, TypeId};
55use std::collections::{BTreeMap, HashMap};
56use std::hash::{Hash, Hasher};
57use std::marker::PhantomData;
58use std::sync::Arc;
59use std::time::Duration;
60
61use crate::scalar::{ScalarOperand, ScalarOrArray};
62use crate::{Array, Category, DType, Device, Error, Result};
63
64#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
66pub enum LeafKind {
67 Array,
69 Param,
71 Buffer,
73}
74
75#[derive(Debug, Clone, Default)]
81pub struct Param {
82 value: Array,
83 frozen: bool,
84}
85
86impl Param {
87 pub fn new(value: Array) -> Self {
89 Self {
90 value,
91 frozen: false,
92 }
93 }
94
95 pub fn frozen(value: Array) -> Self {
97 Self {
98 value,
99 frozen: true,
100 }
101 }
102
103 pub fn is_frozen(&self) -> bool {
105 self.frozen
106 }
107
108 pub fn set_frozen(&mut self, frozen: bool) {
110 self.frozen = frozen;
111 }
112
113 pub fn value(&self) -> &Array {
115 &self.value
116 }
117
118 pub fn value_mut(&mut self) -> &mut Array {
120 &mut self.value
121 }
122
123 pub fn into_inner(self) -> Array {
125 self.value
126 }
127}
128
129impl std::ops::Deref for Param {
130 type Target = Array;
131 fn deref(&self) -> &Array {
132 &self.value
133 }
134}
135
136impl AsRef<Array> for Param {
137 fn as_ref(&self) -> &Array {
138 &self.value
139 }
140}
141
142impl From<Array> for Param {
143 fn from(value: Array) -> Self {
144 Self::new(value)
145 }
146}
147
148impl From<Param> for Array {
149 fn from(p: Param) -> Self {
150 p.value
151 }
152}
153
154impl From<&Param> for ScalarOrArray {
155 fn from(p: &Param) -> Self {
156 Self::Array(p.value.clone())
157 }
158}
159
160impl From<Param> for ScalarOrArray {
161 fn from(p: Param) -> Self {
162 Self::Array(p.value)
163 }
164}
165
166impl<'a> From<&'a Param> for Option<&'a Array> {
168 fn from(p: &'a Param) -> Self {
169 Some(&p.value)
170 }
171}
172
173impl std::fmt::Display for Param {
174 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
175 std::fmt::Display::fmt(&self.value, f)
176 }
177}
178
179macro_rules! param_operators {
182 ($($trait:ident $method:ident),*) => {$(
183 impl std::ops::$trait<&Param> for &Array {
184 type Output = Array;
185 #[track_caller]
186 fn $method(self, rhs: &Param) -> Array {
187 std::ops::$trait::$method(self, &rhs.value)
188 }
189 }
190 impl std::ops::$trait<Param> for &Array {
191 type Output = Array;
192 #[track_caller]
193 fn $method(self, rhs: Param) -> Array {
194 std::ops::$trait::$method(self, &rhs.value)
195 }
196 }
197 impl std::ops::$trait<&Param> for Array {
198 type Output = Array;
199 #[track_caller]
200 fn $method(self, rhs: &Param) -> Array {
201 std::ops::$trait::$method(&self, &rhs.value)
202 }
203 }
204 impl std::ops::$trait<Param> for Array {
205 type Output = Array;
206 #[track_caller]
207 fn $method(self, rhs: Param) -> Array {
208 std::ops::$trait::$method(&self, &rhs.value)
209 }
210 }
211 impl std::ops::$trait<&Array> for &Param {
212 type Output = Array;
213 #[track_caller]
214 fn $method(self, rhs: &Array) -> Array {
215 std::ops::$trait::$method(&self.value, rhs)
216 }
217 }
218 impl std::ops::$trait<Array> for &Param {
219 type Output = Array;
220 #[track_caller]
221 fn $method(self, rhs: Array) -> Array {
222 std::ops::$trait::$method(&self.value, &rhs)
223 }
224 }
225 impl std::ops::$trait<&Array> for Param {
226 type Output = Array;
227 #[track_caller]
228 fn $method(self, rhs: &Array) -> Array {
229 std::ops::$trait::$method(&self.value, rhs)
230 }
231 }
232 impl std::ops::$trait<Array> for Param {
233 type Output = Array;
234 #[track_caller]
235 fn $method(self, rhs: Array) -> Array {
236 std::ops::$trait::$method(&self.value, &rhs)
237 }
238 }
239 impl std::ops::$trait<&Param> for &Param {
240 type Output = Array;
241 #[track_caller]
242 fn $method(self, rhs: &Param) -> Array {
243 std::ops::$trait::$method(&self.value, &rhs.value)
244 }
245 }
246 impl std::ops::$trait<Param> for Param {
247 type Output = Array;
248 #[track_caller]
249 fn $method(self, rhs: Param) -> Array {
250 std::ops::$trait::$method(&self.value, &rhs.value)
251 }
252 }
253 impl<S: ScalarOperand> std::ops::$trait<S> for &Param {
254 type Output = Array;
255 #[track_caller]
256 fn $method(self, rhs: S) -> Array {
257 std::ops::$trait::$method(&self.value, rhs)
258 }
259 }
260 impl<S: ScalarOperand> std::ops::$trait<S> for Param {
261 type Output = Array;
262 #[track_caller]
263 fn $method(self, rhs: S) -> Array {
264 std::ops::$trait::$method(&self.value, rhs)
265 }
266 }
267 )*};
268}
269
270param_operators!(Add add, Sub sub, Mul mul, Div div);
271
272impl std::ops::Neg for &Param {
273 type Output = Array;
274 #[track_caller]
275 fn neg(self) -> Array {
276 -&self.value
277 }
278}
279
280#[diagnostic::on_unimplemented(
291 message = "`{Self}` is not `Static`, so a `#[tree(skip)]` field of this type cannot be hashed into the tree's structure",
292 note = "derive `Static` for it (`#[derive(Static)]`), or mark the field `#[tree(skip, static_unchecked)]` (its value is then baked into compiled traces)"
293)]
294pub trait Static: 'static {
295 fn hash_static(&self, h: &mut dyn Hasher);
297}
298
299macro_rules! static_by_hash {
300 ($($t:ty),*) => {$(
301 impl Static for $t {
302 fn hash_static(&self, mut h: &mut dyn Hasher) {
303 Hash::hash(self, &mut h);
304 }
305 }
306 )*};
307}
308
309static_by_hash!(
310 u8,
311 u16,
312 u32,
313 u64,
314 u128,
315 usize,
316 i8,
317 i16,
318 i32,
319 i64,
320 i128,
321 isize,
322 bool,
323 char,
324 (),
325 String,
326 &'static str,
327 DType,
328 Device,
329 Duration
330);
331
332impl Static for f32 {
333 fn hash_static(&self, h: &mut dyn Hasher) {
334 h.write_u32(self.to_bits());
335 }
336}
337
338impl Static for f64 {
339 fn hash_static(&self, h: &mut dyn Hasher) {
340 h.write_u64(self.to_bits());
341 }
342}
343
344impl<T: Static> Static for Option<T> {
345 fn hash_static(&self, h: &mut dyn Hasher) {
346 match self {
347 None => h.write_u8(0),
348 Some(v) => {
349 h.write_u8(1);
350 v.hash_static(h);
351 }
352 }
353 }
354}
355
356impl<T: Static> Static for Vec<T> {
357 fn hash_static(&self, h: &mut dyn Hasher) {
358 h.write_usize(self.len());
359 for v in self {
360 v.hash_static(h);
361 }
362 }
363}
364
365impl<T: Static, const N: usize> Static for [T; N] {
366 fn hash_static(&self, h: &mut dyn Hasher) {
367 for v in self {
368 v.hash_static(h);
369 }
370 }
371}
372
373impl<T: Static + ?Sized> Static for Box<T> {
374 fn hash_static(&self, h: &mut dyn Hasher) {
375 (**self).hash_static(h);
376 }
377}
378
379impl<T: Static + ?Sized> Static for Arc<T> {
380 fn hash_static(&self, h: &mut dyn Hasher) {
381 (**self).hash_static(h);
382 }
383}
384
385impl<T: 'static> Static for PhantomData<T> {
386 fn hash_static(&self, _: &mut dyn Hasher) {}
387}
388
389macro_rules! static_tuples {
390 ($(($($t:ident $i:tt),+)),*) => {$(
391 impl<$($t: Static),+> Static for ($($t,)+) {
392 fn hash_static(&self, h: &mut dyn Hasher) {
393 $(self.$i.hash_static(h);)+
394 }
395 }
396 )*};
397}
398
399static_tuples!(
400 (A 0),
401 (A 0, B 1),
402 (A 0, B 1, C 2),
403 (A 0, B 1, C 2, D 3),
404 (A 0, B 1, C 2, D 3, E 4),
405 (A 0, B 1, C 2, D 3, E 4, F 5),
406 (A 0, B 1, C 2, D 3, E 4, F 5, G 6),
407 (A 0, B 1, C 2, D 3, E 4, F 5, G 6, H 7)
408);
409
410pub trait Visitor {
415 fn leaf(&mut self, path: &str, array: &Array, kind: LeafKind, trainable: bool);
417 fn paths(&self) -> bool {
420 true
421 }
422 fn enter(&mut self, path: &str, name: &str, type_name: &'static str) {
425 let _ = (path, name, type_name);
426 }
427 fn exit(&mut self, path: &str) {
429 let _ = path;
430 }
431 fn variant(&mut self, path: &str, index: u32) {
433 let _ = (path, index);
434 }
435 fn mode(&mut self, path: &str, training: bool) {
437 let _ = (path, training);
438 }
439 fn static_field(&mut self, path: &str, value: &dyn Static) {
441 let _ = (path, value);
442 }
443}
444
445fn push(path: &mut String, name: &str) -> usize {
448 let len = path.len();
449 if !name.is_empty() {
450 if !path.is_empty() {
451 path.push('.');
452 }
453 path.push_str(name);
454 }
455 len
456}
457
458pub struct Visit<'a> {
461 path: String,
462 paths: bool,
463 visitor: &'a mut dyn Visitor,
464}
465
466impl<'a> Visit<'a> {
467 pub fn new(visitor: &'a mut dyn Visitor) -> Self {
469 Self {
470 path: String::new(),
471 paths: visitor.paths(),
472 visitor,
473 }
474 }
475
476 fn push(&mut self, name: &str) -> usize {
477 if self.paths {
478 push(&mut self.path, name)
479 } else {
480 0
481 }
482 }
483
484 pub fn path(&self) -> &str {
486 &self.path
487 }
488
489 fn leaf(&mut self, name: &str, a: &Array, kind: LeafKind, trainable: bool) {
490 let len = self.push(name);
491 self.visitor.leaf(&self.path, a, kind, trainable);
492 self.path.truncate(len);
493 }
494
495 pub fn array(&mut self, name: &str, a: &Array) {
497 self.leaf(name, a, LeafKind::Array, true);
498 }
499
500 pub fn param(&mut self, name: &str, p: &Param) {
502 self.leaf(name, &p.value, LeafKind::Param, !p.frozen);
503 }
504
505 pub fn buffer(&mut self, name: &str, a: &Array) {
507 self.leaf(name, a, LeafKind::Buffer, false);
508 }
509
510 pub fn child<T: Leaves + ?Sized>(&mut self, name: &str, t: &T) {
512 let len = self.push(name);
513 self.visitor
514 .enter(&self.path, name, std::any::type_name::<T>());
515 t.visit(self);
516 self.visitor.exit(&self.path);
517 self.path.truncate(len);
518 }
519
520 pub fn variant(&mut self, index: u32) {
522 self.visitor.variant(&self.path, index);
523 }
524
525 pub fn mode(&mut self, training: bool) {
527 self.visitor.mode(&self.path, training);
528 }
529
530 pub fn static_field(&mut self, name: &str, value: &dyn Static) {
532 let len = self.push(name);
533 self.visitor.static_field(&self.path, value);
534 self.path.truncate(len);
535 }
536}
537
538pub trait VisitorMut {
540 fn leaf(&mut self, path: &str, array: &mut Array, kind: LeafKind, frozen: Option<&mut bool>);
542 fn paths(&self) -> bool {
544 true
545 }
546 fn child(&mut self, path: &str, child: &mut dyn Any) -> bool {
549 let _ = (path, child);
550 true
551 }
552 fn training(&mut self, path: &str, flag: &mut bool) {
554 let _ = (path, flag);
555 }
556}
557
558pub struct VisitMut<'a> {
560 path: String,
561 paths: bool,
562 visitor: &'a mut dyn VisitorMut,
563}
564
565impl<'a> VisitMut<'a> {
566 pub fn new(visitor: &'a mut dyn VisitorMut) -> Self {
568 Self {
569 path: String::new(),
570 paths: visitor.paths(),
571 visitor,
572 }
573 }
574
575 fn push(&mut self, name: &str) -> usize {
576 if self.paths {
577 push(&mut self.path, name)
578 } else {
579 0
580 }
581 }
582
583 pub fn path(&self) -> &str {
585 &self.path
586 }
587
588 pub fn array(&mut self, name: &str, a: &mut Array) {
590 let len = self.push(name);
591 self.visitor.leaf(&self.path, a, LeafKind::Array, None);
592 self.path.truncate(len);
593 }
594
595 pub fn param(&mut self, name: &str, p: &mut Param) {
597 let len = self.push(name);
598 self.visitor.leaf(
599 &self.path,
600 &mut p.value,
601 LeafKind::Param,
602 Some(&mut p.frozen),
603 );
604 self.path.truncate(len);
605 }
606
607 pub fn buffer(&mut self, name: &str, a: &mut Array) {
609 let len = self.push(name);
610 self.visitor.leaf(&self.path, a, LeafKind::Buffer, None);
611 self.path.truncate(len);
612 }
613
614 pub fn child<T: Tree>(&mut self, name: &str, t: &mut T) {
616 let len = self.push(name);
617 if self.visitor.child(&self.path, t) {
618 t.visit_mut(self);
619 }
620 self.path.truncate(len);
621 }
622
623 pub fn training(&mut self, flag: &mut bool) {
625 self.visitor.training(&self.path, flag);
626 }
627}
628
629#[diagnostic::on_unimplemented(
634 message = "`{Self}` is not a tree of arrays",
635 note = "derive `Tree` for it (`#[derive(Clone, Tree)]`), or use a tuple, `Vec`, map or `Option` of arrays"
636)]
637pub trait Leaves {
638 fn visit(&self, v: &mut Visit<'_>);
641}
642
643#[diagnostic::on_unimplemented(
649 message = "`{Self}` is not a tree of arrays",
650 note = "derive `Tree` for it (`#[derive(Clone, Tree)]`), or use a tuple, `Vec`, map or `Option` of arrays"
651)]
652pub trait Tree: Leaves + Clone + 'static {
653 fn visit_mut(&mut self, v: &mut VisitMut<'_>);
656
657 fn for_each(&self, mut f: impl FnMut(&str, &Array)) {
659 struct ForEach<'f>(&'f mut dyn FnMut(&str, &Array));
660 impl Visitor for ForEach<'_> {
661 fn leaf(&mut self, path: &str, a: &Array, _: LeafKind, _: bool) {
662 (self.0)(path, a);
663 }
664 }
665 self.visit(&mut Visit::new(&mut ForEach(&mut f)));
666 }
667
668 fn map(&self, mut f: impl FnMut(&str, &Array) -> Array) -> Self {
671 struct Map<'f>(&'f mut dyn FnMut(&str, &Array) -> Array);
672 impl VisitorMut for Map<'_> {
673 fn leaf(&mut self, path: &str, a: &mut Array, _: LeafKind, _: Option<&mut bool>) {
674 *a = (self.0)(path, a);
675 }
676 }
677 let mut out = self.clone();
678 out.visit_mut(&mut VisitMut::new(&mut Map(&mut f)));
679 out
680 }
681
682 fn leaves(&self) -> Vec<Array> {
684 collect_leaves(self)
685 }
686
687 fn paths(&self) -> Vec<String> {
689 let mut out = Vec::new();
690 self.for_each(|p, _| out.push(p.to_owned()));
691 out
692 }
693
694 fn flatten(&self) -> Vec<(String, Array)> {
696 let mut out = Vec::new();
697 self.for_each(|p, a| out.push((p.to_owned(), a.clone())));
698 out
699 }
700
701 fn unflatten(&self, leaves: impl IntoIterator<Item = Array>) -> Result<Self> {
704 struct Assign<I>(I, usize, usize);
705 impl<I: Iterator<Item = Array>> VisitorMut for Assign<I> {
706 fn leaf(&mut self, _: &str, a: &mut Array, _: LeafKind, _: Option<&mut bool>) {
707 self.2 += 1;
708 if let Some(next) = self.0.next() {
709 *a = next;
710 self.1 += 1;
711 }
712 }
713 fn paths(&self) -> bool {
714 false
715 }
716 }
717 let mut out = self.clone();
718 let mut assign = Assign(leaves.into_iter(), 0, 0);
719 out.visit_mut(&mut VisitMut::new(&mut assign));
720 let (given, expected) = (assign.1 + assign.0.count(), assign.2);
721 if given != expected {
722 return Err(Error::InvalidArgument(format!(
723 "unflatten: {given} leaves for a tree of {expected}"
724 )));
725 }
726 Ok(out)
727 }
728
729 fn load_flat(
735 &mut self,
736 named: impl IntoIterator<Item = (String, Array)>,
737 mode: LoadMode,
738 ) -> Result<()> {
739 load_named(self, named.into_iter().collect(), mode)
740 }
741
742 fn len(&self) -> usize {
744 struct Count(usize);
745 impl Visitor for Count {
746 fn leaf(&mut self, _: &str, _: &Array, _: LeafKind, _: bool) {
747 self.0 += 1;
748 }
749 fn paths(&self) -> bool {
750 false
751 }
752 }
753 let mut c = Count(0);
754 self.visit(&mut Visit::new(&mut c));
755 c.0
756 }
757
758 fn is_empty(&self) -> bool {
760 self.len() == 0
761 }
762
763 fn def(&self) -> TreeDef {
765 TreeDef::of(self)
766 }
767}
768
769pub fn collect_leaves<T: Leaves + ?Sized>(tree: &T) -> Vec<Array> {
771 struct Collect(Vec<Array>);
772 impl Visitor for Collect {
773 fn leaf(&mut self, _: &str, a: &Array, _: LeafKind, _: bool) {
774 self.0.push(a.clone());
775 }
776 fn paths(&self) -> bool {
777 false
778 }
779 }
780 let mut c = Collect(Vec::new());
781 tree.visit(&mut Visit::new(&mut c));
782 c.0
783}
784
785#[non_exhaustive]
787#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
788pub enum LoadMode {
789 #[default]
791 Strict,
792 Partial,
795}
796
797fn load_named<T: Tree>(tree: &mut T, named: Vec<(String, Array)>, mode: LoadMode) -> Result<()> {
798 let mut given: HashMap<String, Array> = HashMap::with_capacity(named.len());
799 let mut problems: Vec<(u8, String)> = Vec::new();
800 for (name, a) in named {
801 if given.contains_key(&name) {
802 return Err(Error::InvalidArgument(format!(
803 "load_flat: {name:?} is given twice"
804 )));
805 }
806 given.insert(name, a);
807 }
808 let mut shapes: Vec<(String, Vec<i32>)> = Vec::new();
809 {
810 struct Shapes<'a>(&'a mut Vec<(String, Vec<i32>)>);
811 impl Visitor for Shapes<'_> {
812 fn leaf(&mut self, path: &str, a: &Array, _: LeafKind, _: bool) {
813 self.0.push((path.to_owned(), a.shape().to_vec()));
814 }
815 }
816 tree.visit(&mut Visit::new(&mut Shapes(&mut shapes)));
817 }
818 let mut seen = std::collections::HashSet::new();
819 for (path, shape) in &shapes {
820 if !seen.insert(path.as_str()) {
821 return Err(Error::InvalidArgument(format!(
822 "load_flat: the tree has the path {path:?} twice"
823 )));
824 }
825 match given.get(path) {
826 Some(a) if a.shape() != shape.as_slice() => problems.push((
827 2,
828 format!("shape: {path} {:?}, expected {shape:?}", a.shape()),
829 )),
830 Some(_) => {}
831 None if mode == LoadMode::Strict => problems.push((0, format!("missing: {path}"))),
832 None => {}
833 }
834 }
835 if mode == LoadMode::Strict {
836 for name in given.keys() {
837 if !seen.contains(name.as_str()) {
838 problems.push((1, format!("unknown: {name}")));
839 }
840 }
841 }
842 if !problems.is_empty() {
843 problems.sort();
844 let n = problems.len();
845 let mut msg = format!("load_flat: {n} problem{}", if n == 1 { "" } else { "s" });
846 for (_, p) in problems {
847 msg.push_str("\n ");
848 msg.push_str(&p);
849 }
850 return Err(Error::InvalidArgument(msg));
851 }
852 struct Assign<'a>(&'a mut HashMap<String, Array>);
853 impl VisitorMut for Assign<'_> {
854 fn leaf(&mut self, path: &str, a: &mut Array, _: LeafKind, _: Option<&mut bool>) {
855 if let Some(v) = self.0.remove(path) {
856 *a = v;
857 }
858 }
859 }
860 tree.visit_mut(&mut VisitMut::new(&mut Assign(&mut given)));
861 Ok(())
862}
863
864#[derive(Clone, PartialEq, Eq, Hash, Debug)]
867enum DefNode {
868 Leaf {
869 path: String,
870 kind: LeafKind,
871 trainable: bool,
872 },
873 Variant {
874 path: String,
875 index: u32,
876 },
877 Mode {
878 path: String,
879 training: bool,
880 },
881}
882
883#[derive(Clone, PartialEq, Eq, Hash, Debug)]
887pub struct TreeDef {
888 root: TypeId,
889 root_name: &'static str,
890 nodes: Vec<DefNode>,
891 statics: u64,
892}
893
894impl TreeDef {
895 pub fn of<T: Leaves + ?Sized + 'static>(tree: &T) -> Self {
897 struct Collect {
898 nodes: Vec<DefNode>,
899 hasher: std::hash::DefaultHasher,
900 }
901 impl Visitor for Collect {
902 fn leaf(&mut self, path: &str, _: &Array, kind: LeafKind, trainable: bool) {
903 self.nodes.push(DefNode::Leaf {
904 path: path.to_owned(),
905 kind,
906 trainable,
907 });
908 }
909 fn variant(&mut self, path: &str, index: u32) {
910 self.nodes.push(DefNode::Variant {
911 path: path.to_owned(),
912 index,
913 });
914 }
915 fn mode(&mut self, path: &str, training: bool) {
916 self.nodes.push(DefNode::Mode {
917 path: path.to_owned(),
918 training,
919 });
920 }
921 fn static_field(&mut self, path: &str, value: &dyn Static) {
922 self.hasher.write(path.as_bytes());
923 self.hasher.write_u8(0xff);
924 value.hash_static(&mut self.hasher);
925 }
926 }
927 let mut c = Collect {
928 nodes: Vec::new(),
929 hasher: std::hash::DefaultHasher::new(),
930 };
931 tree.visit(&mut Visit::new(&mut c));
932 Self {
933 root: TypeId::of::<T>(),
934 root_name: std::any::type_name::<T>(),
935 nodes: c.nodes,
936 statics: c.hasher.finish(),
937 }
938 }
939
940 pub fn type_name(&self) -> &'static str {
942 self.root_name
943 }
944
945 pub fn leaves(&self) -> impl Iterator<Item = (&str, LeafKind, bool)> {
947 self.nodes.iter().filter_map(|n| match n {
948 DefNode::Leaf {
949 path,
950 kind,
951 trainable,
952 } => Some((path.as_str(), *kind, *trainable)),
953 _ => None,
954 })
955 }
956
957 pub fn len(&self) -> usize {
959 self.leaves().count()
960 }
961
962 pub fn is_empty(&self) -> bool {
964 self.len() == 0
965 }
966
967 pub fn difference(&self, other: &TreeDef) -> Option<String> {
969 if self == other {
970 return None;
971 }
972 if self.root != other.root {
973 return Some(format!("type {} vs {}", self.root_name, other.root_name));
974 }
975 let name = |n: &DefNode| match n {
976 DefNode::Leaf {
977 path,
978 kind,
979 trainable,
980 } => format!(
981 "leaf {path:?} ({kind:?}{})",
982 if *trainable { "" } else { ", not trainable" }
983 ),
984 DefNode::Variant { path, index } => format!("variant {index} at {path:?}"),
985 DefNode::Mode { path, training } => {
986 format!(
987 "{} mode at {path:?}",
988 if *training { "train" } else { "eval" }
989 )
990 }
991 };
992 for i in 0..self.nodes.len().max(other.nodes.len()) {
993 match (self.nodes.get(i), other.nodes.get(i)) {
994 (Some(a), Some(b)) if a == b => {}
995 (Some(a), Some(b)) => return Some(format!("{} vs {}", name(a), name(b))),
996 (Some(a), None) => return Some(format!("{} vs nothing", name(a))),
997 (None, Some(b)) => return Some(format!("nothing vs {}", name(b))),
998 (None, None) => {}
999 }
1000 }
1001 Some("different static fields (configuration or hyperparameters)".into())
1002 }
1003}
1004
1005pub(crate) fn broadcast_zero(like: &Array) -> Array {
1010 Array::from(0u8)
1011 .astype(like.dtype())
1012 .broadcast_to(like.shape())
1013}
1014
1015pub(crate) fn differentiable(dtype: DType) -> bool {
1017 matches!(dtype.category(), Category::Float | Category::Complex)
1018}
1019
1020impl Leaves for Array {
1023 fn visit(&self, v: &mut Visit<'_>) {
1024 v.array("", self);
1025 }
1026}
1027
1028impl Tree for Array {
1029 fn visit_mut(&mut self, v: &mut VisitMut<'_>) {
1030 v.array("", self);
1031 }
1032}
1033
1034impl Leaves for Param {
1035 fn visit(&self, v: &mut Visit<'_>) {
1036 v.param("", self);
1037 }
1038}
1039
1040impl Tree for Param {
1041 fn visit_mut(&mut self, v: &mut VisitMut<'_>) {
1042 v.param("", self);
1043 }
1044}
1045
1046impl Leaves for () {
1047 fn visit(&self, _: &mut Visit<'_>) {}
1048}
1049
1050impl Tree for () {
1051 fn visit_mut(&mut self, _: &mut VisitMut<'_>) {}
1052}
1053
1054impl<T: ?Sized> Leaves for PhantomData<T> {
1055 fn visit(&self, _: &mut Visit<'_>) {}
1056}
1057
1058impl<T: ?Sized + 'static> Tree for PhantomData<T> {
1059 fn visit_mut(&mut self, _: &mut VisitMut<'_>) {}
1060}
1061
1062impl<T: Leaves + ?Sized> Leaves for &T {
1063 fn visit(&self, v: &mut Visit<'_>) {
1064 (**self).visit(v);
1065 }
1066}
1067
1068impl<T: Leaves + ?Sized> Leaves for &mut T {
1069 fn visit(&self, v: &mut Visit<'_>) {
1070 (**self).visit(v);
1071 }
1072}
1073
1074impl<T: Leaves> Leaves for Option<T> {
1075 fn visit(&self, v: &mut Visit<'_>) {
1076 match self {
1077 None => v.variant(0),
1078 Some(x) => {
1079 v.variant(1);
1080 v.child("", x);
1081 }
1082 }
1083 }
1084}
1085
1086impl<T: Tree> Tree for Option<T> {
1087 fn visit_mut(&mut self, v: &mut VisitMut<'_>) {
1088 if let Some(x) = self {
1089 v.child("", x);
1090 }
1091 }
1092}
1093
1094impl<T: Leaves> Leaves for Box<T> {
1095 fn visit(&self, v: &mut Visit<'_>) {
1096 v.child("", &**self);
1097 }
1098}
1099
1100impl<T: Tree> Tree for Box<T> {
1101 fn visit_mut(&mut self, v: &mut VisitMut<'_>) {
1102 v.child("", &mut **self);
1103 }
1104}
1105
1106impl<T: Leaves> Leaves for [T] {
1107 fn visit(&self, v: &mut Visit<'_>) {
1108 for (i, x) in self.iter().enumerate() {
1109 v.child(&i.to_string(), x);
1110 }
1111 }
1112}
1113
1114impl<T: Leaves> Leaves for Vec<T> {
1115 fn visit(&self, v: &mut Visit<'_>) {
1116 self.as_slice().visit(v);
1117 }
1118}
1119
1120impl<T: Tree> Tree for Vec<T> {
1121 fn visit_mut(&mut self, v: &mut VisitMut<'_>) {
1122 for (i, x) in self.iter_mut().enumerate() {
1123 v.child(&i.to_string(), x);
1124 }
1125 }
1126}
1127
1128impl<T: Leaves, const N: usize> Leaves for [T; N] {
1129 fn visit(&self, v: &mut Visit<'_>) {
1130 self.as_slice().visit(v);
1131 }
1132}
1133
1134impl<T: Tree, const N: usize> Tree for [T; N] {
1135 fn visit_mut(&mut self, v: &mut VisitMut<'_>) {
1136 for (i, x) in self.iter_mut().enumerate() {
1137 v.child(&i.to_string(), x);
1138 }
1139 }
1140}
1141
1142impl<T: Leaves> Leaves for BTreeMap<String, T> {
1143 fn visit(&self, v: &mut Visit<'_>) {
1144 for (k, x) in self {
1145 v.child(k, x);
1146 }
1147 }
1148}
1149
1150impl<T: Tree> Tree for BTreeMap<String, T> {
1151 fn visit_mut(&mut self, v: &mut VisitMut<'_>) {
1152 for (k, x) in self.iter_mut() {
1153 v.child(k, x);
1154 }
1155 }
1156}
1157
1158impl<T: Leaves, S: 'static> Leaves for HashMap<String, T, S> {
1159 fn visit(&self, v: &mut Visit<'_>) {
1160 let mut entries: Vec<(&String, &T)> = self.iter().collect();
1161 entries.sort_unstable_by(|a, b| a.0.cmp(b.0));
1162 for (k, x) in entries {
1163 v.child(k, x);
1164 }
1165 }
1166}
1167
1168impl<T: Tree, S: std::hash::BuildHasher + Clone + 'static> Tree for HashMap<String, T, S> {
1169 fn visit_mut(&mut self, v: &mut VisitMut<'_>) {
1170 let mut entries: Vec<(&String, &mut T)> = self.iter_mut().collect();
1171 entries.sort_unstable_by(|a, b| a.0.cmp(b.0));
1172 for (k, x) in entries {
1173 v.child(k, x);
1174 }
1175 }
1176}
1177
1178macro_rules! tuples {
1179 ($(($($t:ident $i:tt),+)),*) => {$(
1180 impl<$($t: Leaves),+> Leaves for ($($t,)+) {
1181 fn visit(&self, v: &mut Visit<'_>) {
1182 $(v.child(stringify!($i), &self.$i);)+
1183 }
1184 }
1185 impl<$($t: Tree),+> Tree for ($($t,)+) {
1186 fn visit_mut(&mut self, v: &mut VisitMut<'_>) {
1187 $(v.child(stringify!($i), &mut self.$i);)+
1188 }
1189 }
1190 )*};
1191}
1192
1193tuples!(
1194 (A 0),
1195 (A 0, B 1),
1196 (A 0, B 1, C 2),
1197 (A 0, B 1, C 2, D 3),
1198 (A 0, B 1, C 2, D 3, E 4),
1199 (A 0, B 1, C 2, D 3, E 4, F 5),
1200 (A 0, B 1, C 2, D 3, E 4, F 5, G 6),
1201 (A 0, B 1, C 2, D 3, E 4, F 5, G 6, H 7)
1202);
1203
1204#[doc(hidden)]
1207pub mod __derive {
1208 pub use std::any::TypeId;
1209 pub use std::clone::Clone;
1210 pub use std::hash::Hasher;
1211 pub use std::marker::PhantomData;
1212
1213 pub use super::{LeafKind, Leaves, Param, Static, Tree, Visit, VisitMut};
1214 pub use crate::Array;
1215
1216 pub const fn assert_static<T: Static + ?Sized>() {}
1218}