use core::ops::AddAssign;
use super::*;
pub mod macros;
pub struct Tensor<const M: usize, const N: usize, F>
where
[(); M * N]:,
{
coefficients: V<M, V<N, F>>,
}
impl<const M: usize, const N: usize, F> Default for Tensor<M, N, F>
where
[(); M * N]:,
F: Default + Copy,
{
fn default() -> Self {
let coefficients = V::<M, V<N, F>>::default();
Tensor { coefficients }
}
}
impl<const M: usize, const N: usize, F> Tensor<M, N, F>
where
[(); M * N]:,
F: Mul<Output = F> + Default + Copy,
{
pub fn tensor_product<const P: usize>(v: [V<M, F>; P], w: [V<N, F>; P]) -> Tensor<M, N, F> {
let mut tensor = Tensor::default();
for p in 0..P {
for i in 0..M {
for j in 0..N {
tensor.coefficients.0[i].0[j] = v[p].0[i] * w[p].0[j];
}
}
}
tensor
}
}
impl<const M: usize, const N: usize, F> Add for Tensor<M, N, F>
where
[(); M * N]:,
F: Add<Output = F> + Copy + Default,
{
type Output = Self;
fn add(self, other: Tensor<M, N, F>) -> Self::Output {
let mut tensor = Tensor::default();
for i in 0..M {
for j in 0..N {
tensor.coefficients.0[i].0[j] =
self.coefficients.0[i].0[j] + other.coefficients.0[i].0[j];
}
}
tensor
}
}
impl<const M: usize, const N: usize, F> Mul<F> for Tensor<M, N, F>
where
[(); M * N]:,
F: Mul<Output = F> + Default + Copy,
{
type Output = Self;
fn mul(self, scalar: F) -> Self::Output {
let mut tensor = Tensor::default();
for i in 0..M {
for j in 0..N {
tensor.coefficients.0[i].0[j] = self.coefficients.0[i].0[j] * scalar;
}
}
tensor
}
}
impl<const M: usize, const N: usize, F> Tensor<M, N, F>
where
[(); M * N]:,
F: Add<Output = F> + Mul<Output = F> + AddAssign + Default + Copy,
{
pub fn bilinear_map(&self, v: V<M, F>, w: V<N, F>) -> F {
let mut sum = F::default();
for i in 0..M {
for j in 0..N {
sum += v.0[j] * self.coefficients.0[i].0[j] * w.0[i];
}
}
sum
}
#[allow(non_snake_case)]
pub fn get_functional_on_V(&self, w: V<N, F>) -> impl Fn(V<M, F>) -> F + '_ {
move |v| self.bilinear_map(v, w)
}
#[allow(non_snake_case)]
pub fn get_functional_on_W(&self, v: V<M, F>) -> impl Fn(V<N, F>) -> F + '_ {
move |w| self.bilinear_map(v, w)
}
#[allow(non_snake_case)]
pub fn linear_map_V_to_W(&self, v: V<M, F>) -> V<N, F> {
let mut w = V([F::default(); N]);
for j in 0..N {
for i in 0..M {
w.0[j] += self.coefficients.0[i].0[j] * v.0[j];
}
}
w
}
#[allow(non_snake_case)]
pub fn linear_map_W_to_V(&self, w: V<N, F>) -> V<M, F> {
let mut v = V([F::default(); M]);
for j in 0..N {
for i in 0..M {
v.0[j] += self.coefficients.0[i].0[j] * w.0[i];
}
}
v
}
}
impl<const M: usize, const N: usize, const P: usize, F> Mul<Tensor<N, P, F>> for Tensor<M, N, F>
where
[(); M * N]:,
[(); N * P]:,
F: Add<Output = F> + AddAssign + Mul<Output = F> + Default + Copy,
{
type Output = Self;
fn mul(self, other: Tensor<N, P, F>) -> Self::Output {
let mut product = Tensor::default();
for i in 0..N {
for k in 0..P {
for j in 0..M {
product.coefficients.0[j].0[k] +=
self.coefficients.0[i].0[j] * other.coefficients.0[j].0[k];
}
}
}
product
}
}