optimath/
templatemetamath.rs

1//! build calculations in the type system, for better locality of operations
2//!
3//! instead of calculating the whole result for each step of the operation
4//! calculate all steps of the operation for each element of the result.
5//!
6//! this might lead to less memory bandwidth used, as data gets worked on in one go.
7//! might also lead to less cache locality tough, as elements from all inputs are used
8//! instead of all elements from one (two).
9//! cache locality will be slightly mitigated, as operations will (soon (TM)) run on multiple data
10//! at once.
11
12//todo: add V type that wraps a Vector and implements virtual add/mul/sub/div, just at type to get
13//your calculation started
14
15//todo: add transpose/matrix multiplication, potentially switch from basing this off off ConstIndex
16//to ConstIter
17
18use crate::consts::{ConstIndex, ConstIterator};
19use core::ops::*;
20
21pub struct VAdd<T, L, R, LT, RT, const N: usize>
22where
23	// use Borrow maybe?
24	// hard to abstract over lifetimes + owned/borrowd
25	L: ConstIndex<LT, N> + Copy + Clone,
26	R: ConstIndex<RT, N> + Copy + Clone,
27	LT: Add<RT, Output = T>,
28{
29	l: L,
30	r: R,
31	m: core::marker::PhantomData<(T, LT, RT)>,
32}
33
34impl<T, L, R, LT, RT, const N: usize> Copy for VAdd<T, L, R, LT, RT, N>
35where
36	L: ConstIndex<LT, N> + Copy + Clone,
37	R: ConstIndex<RT, N> + Copy + Clone,
38	LT: Add<RT, Output = T>,
39{
40}
41
42impl<T, L, R, LT, RT, const N: usize> Clone for VAdd<T, L, R, LT, RT, N>
43where
44	L: ConstIndex<LT, N> + Copy + Clone,
45	R: ConstIndex<RT, N> + Copy + Clone,
46	LT: Add<RT, Output = T>,
47{
48	fn clone(&self) -> Self { *self }
49}
50
51// this is safe because the underlying ConstIndex implementations are guaranteed to be safe
52unsafe impl<T, L, R, LT, RT, const N: usize> ConstIndex<T, N> for VAdd<T, L, R, LT, RT, N>
53where
54	L: ConstIndex<LT, N> + Copy + Clone,
55	R: ConstIndex<RT, N> + Copy + Clone,
56	LT: Add<RT, Output = T>,
57{
58	#[inline]
59	fn i(self, index: usize) -> T {
60		let l = self.l.i(index);
61		let r = self.r.i(index);
62		l + r
63	}
64}
65
66// this restricts other to const-Index to the same type as self
67//
68// this is not a necessary restriction, but rust type system does not allow for expressing anything
69// more generic due to "unconstrained type parameters"
70//
71// this might be possible once GAT lands, allowing for stuff like (X,Y) + (Z,) = (X, Y, Z) or
72// the like. like for example T + &T which is kinda important...
73impl<T, L, R, LT, RT, O, NT, const N: usize> Add<O> for VAdd<T, L, R, LT, RT, N>
74where
75	L: ConstIndex<LT, N> + Copy + Clone,
76	R: ConstIndex<RT, N> + Copy + Clone,
77	LT: Add<RT, Output = T>,
78
79	O: ConstIndex<T, N> + Copy + Clone,
80	T: Add<T, Output = NT>,
81{
82	type Output = VAdd<NT, Self, O, T, T, N>;
83	fn add(self, other: O) -> Self::Output {
84		VAdd {
85			l: self,
86			r: other,
87			m: Default::default(),
88		}
89	}
90}
91
92/*
93// can't even specialize for vector, cause "downstream crates may implement ConstIndex
94// except im already implementing that in this crate...
95use crate::Vector;
96impl<'o, T, L, R, LT, RT, NT, const N: usize> Add<&'o Vector<T, N>> for VAdd<T, L, R, LT, RT, N>
97where
98	L: ConstIndex<LT, N> + Copy + Clone,
99	R: ConstIndex<RT, N> + Copy + Clone,
100	LT: Add<RT, Output = T>,
101
102	T: Add<&'o T, Output = NT>,
103{
104	type Output = VAdd<NT, Self, &'o Vector<T, N>, T, T, N>;
105	fn add(self, other: &'o Vector<T, N>) -> Self::Output {
106		VAdd {
107			l: self,
108			r: other,
109			m: Default::default(),
110		}
111	}
112}
113*/
114//
115impl<T, L, R, LT, RT, const N: usize> VAdd<T, L, R, LT, RT, N>
116where
117	L: ConstIndex<LT, N> + Copy + Clone,
118	R: ConstIndex<RT, N> + Copy + Clone,
119	LT: Add<RT, Output = T>,
120{
121	pub fn new(l: L, r: R) -> Self {
122		Self {
123			l,
124			r,
125			m: Default::default(),
126		}
127	}
128
129	pub fn realize(self) -> crate::Vector<T, N> { ConstIterator::from(self).collect() }
130}
131
132#[cfg(test)]
133pub(crate) const TESTLEN: usize = 777usize;
134
135#[test]
136fn calc_chain() {
137	use crate::Vector;
138	use rand::{thread_rng, Rng};
139	let mut rng = thread_rng();
140	let a: Vector<f32, TESTLEN> = rng.gen();
141	let b: Vector<f32, TESTLEN> = rng.gen();
142	let c: Vector<f32, TESTLEN> = rng.gen();
143	let d: Vector<f32, TESTLEN> = rng.gen();
144	let e: Vector<f32, TESTLEN> = rng.gen();
145
146	let ab = VAdd::new(a, b);
147	let abc = ab + c;
148	let abcd = abc + d;
149	let abcde = abcd + e;
150
151	let _res = abcde.realize();
152}