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: &(impl BufferLeaf + ?Sized)) {
508 if let Some(a) = a.buffer_array() {
509 self.leaf(name, a, LeafKind::Buffer, false);
510 }
511 }
512
513 pub fn child<T: Leaves + ?Sized>(&mut self, name: &str, t: &T) {
515 let len = self.push(name);
516 self.visitor
517 .enter(&self.path, name, std::any::type_name::<T>());
518 t.visit(self);
519 self.visitor.exit(&self.path);
520 self.path.truncate(len);
521 }
522
523 pub fn variant(&mut self, index: u32) {
525 self.visitor.variant(&self.path, index);
526 }
527
528 pub fn mode(&mut self, training: bool) {
530 self.visitor.mode(&self.path, training);
531 }
532
533 pub fn static_field(&mut self, name: &str, value: &dyn Static) {
535 let len = self.push(name);
536 self.visitor.static_field(&self.path, value);
537 self.path.truncate(len);
538 }
539}
540
541pub trait BufferLeaf {
544 fn buffer_array(&self) -> Option<&Array>;
546 fn buffer_array_mut(&mut self) -> Option<&mut Array>;
548}
549
550impl BufferLeaf for Array {
551 fn buffer_array(&self) -> Option<&Array> {
552 Some(self)
553 }
554
555 fn buffer_array_mut(&mut self) -> Option<&mut Array> {
556 Some(self)
557 }
558}
559
560impl BufferLeaf for Option<Array> {
561 fn buffer_array(&self) -> Option<&Array> {
562 self.as_ref()
563 }
564
565 fn buffer_array_mut(&mut self) -> Option<&mut Array> {
566 self.as_mut()
567 }
568}
569
570pub trait VisitorMut {
572 fn leaf(&mut self, path: &str, array: &mut Array, kind: LeafKind, frozen: Option<&mut bool>);
574 fn paths(&self) -> bool {
576 true
577 }
578 fn child(&mut self, path: &str, child: &mut dyn Any) -> bool {
581 let _ = (path, child);
582 true
583 }
584 fn training(&mut self, path: &str, flag: &mut bool) {
586 let _ = (path, flag);
587 }
588}
589
590pub struct VisitMut<'a> {
592 path: String,
593 paths: bool,
594 visitor: &'a mut dyn VisitorMut,
595}
596
597impl<'a> VisitMut<'a> {
598 pub fn new(visitor: &'a mut dyn VisitorMut) -> Self {
600 Self {
601 path: String::new(),
602 paths: visitor.paths(),
603 visitor,
604 }
605 }
606
607 fn push(&mut self, name: &str) -> usize {
608 if self.paths {
609 push(&mut self.path, name)
610 } else {
611 0
612 }
613 }
614
615 pub fn path(&self) -> &str {
617 &self.path
618 }
619
620 pub fn array(&mut self, name: &str, a: &mut Array) {
622 let len = self.push(name);
623 self.visitor.leaf(&self.path, a, LeafKind::Array, None);
624 self.path.truncate(len);
625 }
626
627 pub fn param(&mut self, name: &str, p: &mut Param) {
629 let len = self.push(name);
630 self.visitor.leaf(
631 &self.path,
632 &mut p.value,
633 LeafKind::Param,
634 Some(&mut p.frozen),
635 );
636 self.path.truncate(len);
637 }
638
639 pub fn buffer(&mut self, name: &str, a: &mut (impl BufferLeaf + ?Sized)) {
641 let Some(a) = a.buffer_array_mut() else {
642 return;
643 };
644 let len = self.push(name);
645 self.visitor.leaf(&self.path, a, LeafKind::Buffer, None);
646 self.path.truncate(len);
647 }
648
649 pub fn child<T: Tree>(&mut self, name: &str, t: &mut T) {
651 let len = self.push(name);
652 if self.visitor.child(&self.path, t) {
653 t.visit_mut(self);
654 }
655 self.path.truncate(len);
656 }
657
658 pub fn training(&mut self, flag: &mut bool) {
660 self.visitor.training(&self.path, flag);
661 }
662}
663
664#[diagnostic::on_unimplemented(
669 message = "`{Self}` is not a tree of arrays",
670 note = "derive `Tree` for it (`#[derive(Clone, Tree)]`), or use a tuple, `Vec`, map or `Option` of arrays"
671)]
672pub trait Leaves {
673 fn visit(&self, v: &mut Visit<'_>);
676}
677
678#[diagnostic::on_unimplemented(
684 message = "`{Self}` is not a tree of arrays",
685 note = "derive `Tree` for it (`#[derive(Clone, Tree)]`), or use a tuple, `Vec`, map or `Option` of arrays"
686)]
687pub trait Tree: Leaves + Clone + 'static {
688 fn visit_mut(&mut self, v: &mut VisitMut<'_>);
691
692 fn for_each(&self, mut f: impl FnMut(&str, &Array)) {
694 struct ForEach<'f>(&'f mut dyn FnMut(&str, &Array));
695 impl Visitor for ForEach<'_> {
696 fn leaf(&mut self, path: &str, a: &Array, _: LeafKind, _: bool) {
697 (self.0)(path, a);
698 }
699 }
700 self.visit(&mut Visit::new(&mut ForEach(&mut f)));
701 }
702
703 fn map(&self, mut f: impl FnMut(&str, &Array) -> Array) -> Self {
706 struct Map<'f>(&'f mut dyn FnMut(&str, &Array) -> Array);
707 impl VisitorMut for Map<'_> {
708 fn leaf(&mut self, path: &str, a: &mut Array, _: LeafKind, _: Option<&mut bool>) {
709 *a = (self.0)(path, a);
710 }
711 }
712 let mut out = self.clone();
713 out.visit_mut(&mut VisitMut::new(&mut Map(&mut f)));
714 out
715 }
716
717 fn leaves(&self) -> Vec<Array> {
719 collect_leaves(self)
720 }
721
722 fn paths(&self) -> Vec<String> {
724 let mut out = Vec::new();
725 self.for_each(|p, _| out.push(p.to_owned()));
726 out
727 }
728
729 fn flatten(&self) -> Vec<(String, Array)> {
731 let mut out = Vec::new();
732 self.for_each(|p, a| out.push((p.to_owned(), a.clone())));
733 out
734 }
735
736 fn unflatten(&self, leaves: impl IntoIterator<Item = Array>) -> Result<Self> {
739 struct Assign<I>(I, usize, usize);
740 impl<I: Iterator<Item = Array>> VisitorMut for Assign<I> {
741 fn leaf(&mut self, _: &str, a: &mut Array, _: LeafKind, _: Option<&mut bool>) {
742 self.2 += 1;
743 if let Some(next) = self.0.next() {
744 *a = next;
745 self.1 += 1;
746 }
747 }
748 fn paths(&self) -> bool {
749 false
750 }
751 }
752 let mut out = self.clone();
753 let mut assign = Assign(leaves.into_iter(), 0, 0);
754 out.visit_mut(&mut VisitMut::new(&mut assign));
755 let (given, expected) = (assign.1 + assign.0.count(), assign.2);
756 if given != expected {
757 return Err(Error::InvalidArgument(format!(
758 "unflatten: {given} leaves for a tree of {expected}"
759 )));
760 }
761 Ok(out)
762 }
763
764 fn load_flat(
770 &mut self,
771 named: impl IntoIterator<Item = (String, Array)>,
772 mode: LoadMode,
773 ) -> Result<()> {
774 load_named(self, named.into_iter().collect(), mode)
775 }
776
777 fn len(&self) -> usize {
779 struct Count(usize);
780 impl Visitor for Count {
781 fn leaf(&mut self, _: &str, _: &Array, _: LeafKind, _: bool) {
782 self.0 += 1;
783 }
784 fn paths(&self) -> bool {
785 false
786 }
787 }
788 let mut c = Count(0);
789 self.visit(&mut Visit::new(&mut c));
790 c.0
791 }
792
793 fn is_empty(&self) -> bool {
795 self.len() == 0
796 }
797
798 fn def(&self) -> TreeDef {
800 TreeDef::of(self)
801 }
802}
803
804pub fn collect_leaves<T: Leaves + ?Sized>(tree: &T) -> Vec<Array> {
806 struct Collect(Vec<Array>);
807 impl Visitor for Collect {
808 fn leaf(&mut self, _: &str, a: &Array, _: LeafKind, _: bool) {
809 self.0.push(a.clone());
810 }
811 fn paths(&self) -> bool {
812 false
813 }
814 }
815 let mut c = Collect(Vec::new());
816 tree.visit(&mut Visit::new(&mut c));
817 c.0
818}
819
820#[non_exhaustive]
822#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
823pub enum LoadMode {
824 #[default]
826 Strict,
827 Partial,
830}
831
832fn load_named<T: Tree>(tree: &mut T, named: Vec<(String, Array)>, mode: LoadMode) -> Result<()> {
833 let mut given: HashMap<String, Array> = HashMap::with_capacity(named.len());
834 let mut problems: Vec<(u8, String)> = Vec::new();
835 for (name, a) in named {
836 if given.contains_key(&name) {
837 return Err(Error::InvalidArgument(format!(
838 "load_flat: {name:?} is given twice"
839 )));
840 }
841 given.insert(name, a);
842 }
843 let mut shapes: Vec<(String, Vec<i32>)> = Vec::new();
844 {
845 struct Shapes<'a>(&'a mut Vec<(String, Vec<i32>)>);
846 impl Visitor for Shapes<'_> {
847 fn leaf(&mut self, path: &str, a: &Array, _: LeafKind, _: bool) {
848 self.0.push((path.to_owned(), a.shape().to_vec()));
849 }
850 }
851 tree.visit(&mut Visit::new(&mut Shapes(&mut shapes)));
852 }
853 let mut seen = std::collections::HashSet::new();
854 for (path, shape) in &shapes {
855 if !seen.insert(path.as_str()) {
856 return Err(Error::InvalidArgument(format!(
857 "load_flat: the tree has the path {path:?} twice"
858 )));
859 }
860 match given.get(path) {
861 Some(a) if a.shape() != shape.as_slice() => problems.push((
862 2,
863 format!("shape: {path} {:?}, expected {shape:?}", a.shape()),
864 )),
865 Some(_) => {}
866 None if mode == LoadMode::Strict => problems.push((0, format!("missing: {path}"))),
867 None => {}
868 }
869 }
870 if mode == LoadMode::Strict {
871 for name in given.keys() {
872 if !seen.contains(name.as_str()) {
873 problems.push((1, format!("unknown: {name}")));
874 }
875 }
876 }
877 if !problems.is_empty() {
878 problems.sort();
879 let n = problems.len();
880 let mut msg = format!("load_flat: {n} problem{}", if n == 1 { "" } else { "s" });
881 for (_, p) in problems {
882 msg.push_str("\n ");
883 msg.push_str(&p);
884 }
885 return Err(Error::InvalidArgument(msg));
886 }
887 struct Assign<'a>(&'a mut HashMap<String, Array>);
888 impl VisitorMut for Assign<'_> {
889 fn leaf(&mut self, path: &str, a: &mut Array, _: LeafKind, _: Option<&mut bool>) {
890 if let Some(v) = self.0.remove(path) {
891 *a = v;
892 }
893 }
894 }
895 tree.visit_mut(&mut VisitMut::new(&mut Assign(&mut given)));
896 Ok(())
897}
898
899#[derive(Clone, PartialEq, Eq, Hash, Debug)]
902enum DefNode {
903 Leaf {
904 path: String,
905 kind: LeafKind,
906 trainable: bool,
907 },
908 Variant {
909 path: String,
910 index: u32,
911 },
912 Mode {
913 path: String,
914 training: bool,
915 },
916}
917
918#[derive(Clone, PartialEq, Eq, Hash, Debug)]
922pub struct TreeDef {
923 root: TypeId,
924 root_name: &'static str,
925 nodes: Vec<DefNode>,
926 statics: u64,
927}
928
929impl TreeDef {
930 pub fn of<T: Leaves + ?Sized + 'static>(tree: &T) -> Self {
932 struct Collect {
933 nodes: Vec<DefNode>,
934 hasher: std::hash::DefaultHasher,
935 }
936 impl Visitor for Collect {
937 fn leaf(&mut self, path: &str, _: &Array, kind: LeafKind, trainable: bool) {
938 self.nodes.push(DefNode::Leaf {
939 path: path.to_owned(),
940 kind,
941 trainable,
942 });
943 }
944 fn variant(&mut self, path: &str, index: u32) {
945 self.nodes.push(DefNode::Variant {
946 path: path.to_owned(),
947 index,
948 });
949 }
950 fn mode(&mut self, path: &str, training: bool) {
951 self.nodes.push(DefNode::Mode {
952 path: path.to_owned(),
953 training,
954 });
955 }
956 fn static_field(&mut self, path: &str, value: &dyn Static) {
957 self.hasher.write(path.as_bytes());
958 self.hasher.write_u8(0xff);
959 value.hash_static(&mut self.hasher);
960 }
961 }
962 let mut c = Collect {
963 nodes: Vec::new(),
964 hasher: std::hash::DefaultHasher::new(),
965 };
966 tree.visit(&mut Visit::new(&mut c));
967 Self {
968 root: TypeId::of::<T>(),
969 root_name: std::any::type_name::<T>(),
970 nodes: c.nodes,
971 statics: c.hasher.finish(),
972 }
973 }
974
975 pub fn type_name(&self) -> &'static str {
977 self.root_name
978 }
979
980 pub fn leaves(&self) -> impl Iterator<Item = (&str, LeafKind, bool)> {
982 self.nodes.iter().filter_map(|n| match n {
983 DefNode::Leaf {
984 path,
985 kind,
986 trainable,
987 } => Some((path.as_str(), *kind, *trainable)),
988 _ => None,
989 })
990 }
991
992 pub fn len(&self) -> usize {
994 self.leaves().count()
995 }
996
997 pub fn is_empty(&self) -> bool {
999 self.len() == 0
1000 }
1001
1002 pub fn difference(&self, other: &TreeDef) -> Option<String> {
1004 if self == other {
1005 return None;
1006 }
1007 if self.root != other.root {
1008 return Some(format!("type {} vs {}", self.root_name, other.root_name));
1009 }
1010 let name = |n: &DefNode| match n {
1011 DefNode::Leaf {
1012 path,
1013 kind,
1014 trainable,
1015 } => format!(
1016 "leaf {path:?} ({kind:?}{})",
1017 if *trainable { "" } else { ", not trainable" }
1018 ),
1019 DefNode::Variant { path, index } => format!("variant {index} at {path:?}"),
1020 DefNode::Mode { path, training } => {
1021 format!(
1022 "{} mode at {path:?}",
1023 if *training { "train" } else { "eval" }
1024 )
1025 }
1026 };
1027 for i in 0..self.nodes.len().max(other.nodes.len()) {
1028 match (self.nodes.get(i), other.nodes.get(i)) {
1029 (Some(a), Some(b)) if a == b => {}
1030 (Some(a), Some(b)) => return Some(format!("{} vs {}", name(a), name(b))),
1031 (Some(a), None) => return Some(format!("{} vs nothing", name(a))),
1032 (None, Some(b)) => return Some(format!("nothing vs {}", name(b))),
1033 (None, None) => {}
1034 }
1035 }
1036 Some("different static fields (configuration or hyperparameters)".into())
1037 }
1038}
1039
1040pub(crate) fn broadcast_zero(like: &Array) -> Array {
1045 Array::from(0u8)
1046 .astype(like.dtype())
1047 .broadcast_to(like.shape())
1048}
1049
1050pub(crate) fn differentiable(dtype: DType) -> bool {
1052 matches!(dtype.category(), Category::Float | Category::Complex)
1053}
1054
1055impl Leaves for Array {
1058 fn visit(&self, v: &mut Visit<'_>) {
1059 v.array("", self);
1060 }
1061}
1062
1063impl Tree for Array {
1064 fn visit_mut(&mut self, v: &mut VisitMut<'_>) {
1065 v.array("", self);
1066 }
1067}
1068
1069impl Leaves for Param {
1070 fn visit(&self, v: &mut Visit<'_>) {
1071 v.param("", self);
1072 }
1073}
1074
1075impl Tree for Param {
1076 fn visit_mut(&mut self, v: &mut VisitMut<'_>) {
1077 v.param("", self);
1078 }
1079}
1080
1081impl Leaves for () {
1082 fn visit(&self, _: &mut Visit<'_>) {}
1083}
1084
1085impl Tree for () {
1086 fn visit_mut(&mut self, _: &mut VisitMut<'_>) {}
1087}
1088
1089impl<T: ?Sized> Leaves for PhantomData<T> {
1090 fn visit(&self, _: &mut Visit<'_>) {}
1091}
1092
1093impl<T: ?Sized + 'static> Tree for PhantomData<T> {
1094 fn visit_mut(&mut self, _: &mut VisitMut<'_>) {}
1095}
1096
1097impl<T: Leaves + ?Sized> Leaves for &T {
1098 fn visit(&self, v: &mut Visit<'_>) {
1099 (**self).visit(v);
1100 }
1101}
1102
1103impl<T: Leaves + ?Sized> Leaves for &mut T {
1104 fn visit(&self, v: &mut Visit<'_>) {
1105 (**self).visit(v);
1106 }
1107}
1108
1109impl<T: Leaves> Leaves for Option<T> {
1110 fn visit(&self, v: &mut Visit<'_>) {
1111 match self {
1112 None => v.variant(0),
1113 Some(x) => {
1114 v.variant(1);
1115 v.child("", x);
1116 }
1117 }
1118 }
1119}
1120
1121impl<T: Tree> Tree for Option<T> {
1122 fn visit_mut(&mut self, v: &mut VisitMut<'_>) {
1123 if let Some(x) = self {
1124 v.child("", x);
1125 }
1126 }
1127}
1128
1129impl<T: Leaves> Leaves for Box<T> {
1130 fn visit(&self, v: &mut Visit<'_>) {
1131 v.child("", &**self);
1132 }
1133}
1134
1135impl<T: Tree> Tree for Box<T> {
1136 fn visit_mut(&mut self, v: &mut VisitMut<'_>) {
1137 v.child("", &mut **self);
1138 }
1139}
1140
1141impl<T: Leaves> Leaves for [T] {
1142 fn visit(&self, v: &mut Visit<'_>) {
1143 for (i, x) in self.iter().enumerate() {
1144 v.child(&i.to_string(), x);
1145 }
1146 }
1147}
1148
1149impl<T: Leaves> Leaves for Vec<T> {
1150 fn visit(&self, v: &mut Visit<'_>) {
1151 self.as_slice().visit(v);
1152 }
1153}
1154
1155impl<T: Tree> Tree for Vec<T> {
1156 fn visit_mut(&mut self, v: &mut VisitMut<'_>) {
1157 for (i, x) in self.iter_mut().enumerate() {
1158 v.child(&i.to_string(), x);
1159 }
1160 }
1161}
1162
1163impl<T: Leaves, const N: usize> Leaves for [T; N] {
1164 fn visit(&self, v: &mut Visit<'_>) {
1165 self.as_slice().visit(v);
1166 }
1167}
1168
1169impl<T: Tree, const N: usize> Tree for [T; N] {
1170 fn visit_mut(&mut self, v: &mut VisitMut<'_>) {
1171 for (i, x) in self.iter_mut().enumerate() {
1172 v.child(&i.to_string(), x);
1173 }
1174 }
1175}
1176
1177impl<T: Leaves> Leaves for BTreeMap<String, T> {
1178 fn visit(&self, v: &mut Visit<'_>) {
1179 for (k, x) in self {
1180 v.child(k, x);
1181 }
1182 }
1183}
1184
1185impl<T: Tree> Tree for BTreeMap<String, T> {
1186 fn visit_mut(&mut self, v: &mut VisitMut<'_>) {
1187 for (k, x) in self.iter_mut() {
1188 v.child(k, x);
1189 }
1190 }
1191}
1192
1193impl<T: Leaves, S: 'static> Leaves for HashMap<String, T, S> {
1194 fn visit(&self, v: &mut Visit<'_>) {
1195 let mut entries: Vec<(&String, &T)> = self.iter().collect();
1196 entries.sort_unstable_by(|a, b| a.0.cmp(b.0));
1197 for (k, x) in entries {
1198 v.child(k, x);
1199 }
1200 }
1201}
1202
1203impl<T: Tree, S: std::hash::BuildHasher + Clone + 'static> Tree for HashMap<String, T, S> {
1204 fn visit_mut(&mut self, v: &mut VisitMut<'_>) {
1205 let mut entries: Vec<(&String, &mut T)> = self.iter_mut().collect();
1206 entries.sort_unstable_by(|a, b| a.0.cmp(b.0));
1207 for (k, x) in entries {
1208 v.child(k, x);
1209 }
1210 }
1211}
1212
1213macro_rules! tuples {
1214 ($(($($t:ident $i:tt),+)),*) => {$(
1215 impl<$($t: Leaves),+> Leaves for ($($t,)+) {
1216 fn visit(&self, v: &mut Visit<'_>) {
1217 $(v.child(stringify!($i), &self.$i);)+
1218 }
1219 }
1220 impl<$($t: Tree),+> Tree for ($($t,)+) {
1221 fn visit_mut(&mut self, v: &mut VisitMut<'_>) {
1222 $(v.child(stringify!($i), &mut self.$i);)+
1223 }
1224 }
1225 )*};
1226}
1227
1228tuples!(
1229 (A 0),
1230 (A 0, B 1),
1231 (A 0, B 1, C 2),
1232 (A 0, B 1, C 2, D 3),
1233 (A 0, B 1, C 2, D 3, E 4),
1234 (A 0, B 1, C 2, D 3, E 4, F 5),
1235 (A 0, B 1, C 2, D 3, E 4, F 5, G 6),
1236 (A 0, B 1, C 2, D 3, E 4, F 5, G 6, H 7)
1237);
1238
1239#[doc(hidden)]
1242pub mod __derive {
1243 pub use std::any::TypeId;
1244 pub use std::clone::Clone;
1245 pub use std::hash::Hasher;
1246 pub use std::marker::PhantomData;
1247
1248 pub use super::{LeafKind, Leaves, Param, Static, Tree, Visit, VisitMut};
1249 pub use crate::Array;
1250
1251 pub const fn assert_static<T: Static + ?Sized>() {}
1253}