From 254bc10225509b7c267b667b99970f5a0efae405 Mon Sep 17 00:00:00 2001 From: yanndupis Date: Wed, 30 Jun 2021 17:52:15 -0700 Subject: [PATCH 1/7] Add left to right broadcast for binary ops --- rust/moose/src/standard.rs | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/rust/moose/src/standard.rs b/rust/moose/src/standard.rs index 9b3db020c..7a105e9b7 100644 --- a/rust/moose/src/standard.rs +++ b/rust/moose/src/standard.rs @@ -7,6 +7,7 @@ use ndarray_linalg::types::{Lapack, Scalar}; use ndarray_linalg::*; use num_traits::FromPrimitive; use serde::{Deserialize, Serialize}; +use std::borrow::Borrow; use std::ops::{Add, Div, Mul, Sub}; #[derive(Serialize, Deserialize, PartialEq, Clone, Debug)] @@ -221,7 +222,21 @@ where { type Output = StandardTensor; fn div(self, other: StandardTensor) -> Self::Output { - StandardTensor::(self.0 / other.0) + let lhs_to_rhs_broadcast = self.0.broadcast(other.0.dim()); + match lhs_to_rhs_broadcast { + Some(lhs_broadcasted) => StandardTensor::(lhs_broadcasted.to_owned() / other.0), + None => { + let rhs_to_lhs_broadcast = other.0.broadcast(self.0.dim()); + match rhs_to_lhs_broadcast { + Some(rhs_broadcasted) => StandardTensor::(self.0 / rhs_broadcasted), + None => panic!( + "Div can't broadcast array of shape: {:?} to {:?}", + other.0.dim(), + self.0.dim() + ), + } + } + } } } @@ -387,4 +402,23 @@ mod tests { assert_eq!(cx, c_exp); assert_eq!(dx, d_exp); } + + #[test] + fn test_div() { + let x_1 = StandardTensor::::from(array![1.0].into_dimensionality::().unwrap()); + let y_1 = + StandardTensor::::from(array![2.0, 4.0].into_dimensionality::().unwrap()); + let z_1 = x_1.div(y_1); + let z_1_exp = + StandardTensor::::from(array![0.5, 0.25].into_dimensionality::().unwrap()); + let x_2 = + StandardTensor::::from(array![2.0, 4.0].into_dimensionality::().unwrap()); + let y_2 = StandardTensor::::from(array![2.0].into_dimensionality::().unwrap()); + let z_2 = x_2.div(y_2); + let z_2_exp = + StandardTensor::::from(array![1.0, 2.0].into_dimensionality::().unwrap()); + + assert_eq!(z_1, z_1_exp); + assert_eq!(z_2, z_2_exp); + } } From 26493cb30675994da517e9bbc99b98f5eecdbd43 Mon Sep 17 00:00:00 2001 From: yanndupis Date: Thu, 1 Jul 2021 12:02:05 -0700 Subject: [PATCH 2/7] Refactor div broadcast --- rust/moose/src/standard.rs | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/rust/moose/src/standard.rs b/rust/moose/src/standard.rs index 7a105e9b7..e0e4aa3aa 100644 --- a/rust/moose/src/standard.rs +++ b/rust/moose/src/standard.rs @@ -222,20 +222,9 @@ where { type Output = StandardTensor; fn div(self, other: StandardTensor) -> Self::Output { - let lhs_to_rhs_broadcast = self.0.broadcast(other.0.dim()); - match lhs_to_rhs_broadcast { - Some(lhs_broadcasted) => StandardTensor::(lhs_broadcasted.to_owned() / other.0), - None => { - let rhs_to_lhs_broadcast = other.0.broadcast(self.0.dim()); - match rhs_to_lhs_broadcast { - Some(rhs_broadcasted) => StandardTensor::(self.0 / rhs_broadcasted), - None => panic!( - "Div can't broadcast array of shape: {:?} to {:?}", - other.0.dim(), - self.0.dim() - ), - } - } + match self.0.broadcast(other.0.dim()) { + Some(self_broadcasted) => StandardTensor::(self_broadcasted.to_owned() / other.0), + None => StandardTensor::(self.0 / other.0), } } } From 9c929c3ddcf4e72d7d5a1bf60fc60ceacaabd292 Mon Sep 17 00:00:00 2001 From: yanndupis Date: Thu, 1 Jul 2021 16:16:57 -0700 Subject: [PATCH 3/7] Rename test to test_div_broadcasting --- rust/moose/src/standard.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/rust/moose/src/standard.rs b/rust/moose/src/standard.rs index e0e4aa3aa..6fa3b64f5 100644 --- a/rust/moose/src/standard.rs +++ b/rust/moose/src/standard.rs @@ -7,7 +7,6 @@ use ndarray_linalg::types::{Lapack, Scalar}; use ndarray_linalg::*; use num_traits::FromPrimitive; use serde::{Deserialize, Serialize}; -use std::borrow::Borrow; use std::ops::{Add, Div, Mul, Sub}; #[derive(Serialize, Deserialize, PartialEq, Clone, Debug)] @@ -393,7 +392,7 @@ mod tests { } #[test] - fn test_div() { + fn test_div_broadcasting() { let x_1 = StandardTensor::::from(array![1.0].into_dimensionality::().unwrap()); let y_1 = StandardTensor::::from(array![2.0, 4.0].into_dimensionality::().unwrap()); From cdc1fd2d3d1d18085df70b0524fd0b35bd9bdb96 Mon Sep 17 00:00:00 2001 From: yanndupis Date: Thu, 1 Jul 2021 16:35:23 -0700 Subject: [PATCH 4/7] Implement broadcasting for other binary ops --- rust/moose/src/standard.rs | 72 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 69 insertions(+), 3 deletions(-) diff --git a/rust/moose/src/standard.rs b/rust/moose/src/standard.rs index 6fa3b64f5..540253008 100644 --- a/rust/moose/src/standard.rs +++ b/rust/moose/src/standard.rs @@ -191,7 +191,10 @@ where { type Output = StandardTensor; fn add(self, other: StandardTensor) -> Self::Output { - StandardTensor::(self.0 + other.0) + match self.0.broadcast(other.0.dim()) { + Some(self_broadcasted) => StandardTensor::(self_broadcasted.to_owned() + other.0), + None => StandardTensor::(self.0 + other.0), + } } } @@ -201,7 +204,10 @@ where { type Output = StandardTensor; fn sub(self, other: StandardTensor) -> Self::Output { - StandardTensor::(self.0 - other.0) + match self.0.broadcast(other.0.dim()) { + Some(self_broadcasted) => StandardTensor::(self_broadcasted.to_owned() - other.0), + None => StandardTensor::(self.0 - other.0), + } } } @@ -211,7 +217,10 @@ where { type Output = StandardTensor; fn mul(self, other: StandardTensor) -> Self::Output { - StandardTensor::(self.0 * other.0) + match self.0.broadcast(other.0.dim()) { + Some(self_broadcasted) => StandardTensor::(self_broadcasted.to_owned() * other.0), + None => StandardTensor::(self.0 * other.0), + } } } @@ -391,6 +400,63 @@ mod tests { assert_eq!(dx, d_exp); } + #[test] + fn test_add_broadcasting() { + let x_1 = StandardTensor::::from(array![2.0].into_dimensionality::().unwrap()); + let y_1 = + StandardTensor::::from(array![1.0, 2.0].into_dimensionality::().unwrap()); + let z_1 = x_1.add(y_1); + let z_1_exp = + StandardTensor::::from(array![3.0, 4.0].into_dimensionality::().unwrap()); + let x_2 = + StandardTensor::::from(array![1.0, 2.0].into_dimensionality::().unwrap()); + let y_2 = StandardTensor::::from(array![2.0].into_dimensionality::().unwrap()); + let z_2 = x_2.add(y_2); + let z_2_exp = + StandardTensor::::from(array![3.0, 4.0].into_dimensionality::().unwrap()); + + assert_eq!(z_1, z_1_exp); + assert_eq!(z_2, z_2_exp); + } + + #[test] + fn test_sub_broadcasting() { + let x_1 = StandardTensor::::from(array![2.0].into_dimensionality::().unwrap()); + let y_1 = + StandardTensor::::from(array![1.0, 2.0].into_dimensionality::().unwrap()); + let z_1 = x_1.sub(y_1); + let z_1_exp = + StandardTensor::::from(array![1.0, 0.0].into_dimensionality::().unwrap()); + let x_2 = + StandardTensor::::from(array![1.0, 2.0].into_dimensionality::().unwrap()); + let y_2 = StandardTensor::::from(array![2.0].into_dimensionality::().unwrap()); + let z_2 = x_2.sub(y_2); + let z_2_exp = + StandardTensor::::from(array![-1.0, 0.0].into_dimensionality::().unwrap()); + + assert_eq!(z_1, z_1_exp); + assert_eq!(z_2, z_2_exp); + } + + #[test] + fn test_mul_broadcasting() { + let x_1 = StandardTensor::::from(array![2.0].into_dimensionality::().unwrap()); + let y_1 = + StandardTensor::::from(array![1.0, 2.0].into_dimensionality::().unwrap()); + let z_1 = x_1.mul(y_1); + let z_1_exp = + StandardTensor::::from(array![2.0, 4.0].into_dimensionality::().unwrap()); + let x_2 = + StandardTensor::::from(array![1.0, 2.0].into_dimensionality::().unwrap()); + let y_2 = StandardTensor::::from(array![2.0].into_dimensionality::().unwrap()); + let z_2 = x_2.mul(y_2); + let z_2_exp = + StandardTensor::::from(array![2.0, 4.0].into_dimensionality::().unwrap()); + + assert_eq!(z_1, z_1_exp); + assert_eq!(z_2, z_2_exp); + } + #[test] fn test_div_broadcasting() { let x_1 = StandardTensor::::from(array![1.0].into_dimensionality::().unwrap()); From 6ca4df7473f10ab22835f346314c8db2f6d04459 Mon Sep 17 00:00:00 2001 From: yanndupis Date: Thu, 1 Jul 2021 17:39:34 -0700 Subject: [PATCH 5/7] Add broadcasting for ring binary ops --- rust/moose/src/ring.rs | 84 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 81 insertions(+), 3 deletions(-) diff --git a/rust/moose/src/ring.rs b/rust/moose/src/ring.rs index 5a6530e12..eb167ee45 100644 --- a/rust/moose/src/ring.rs +++ b/rust/moose/src/ring.rs @@ -164,7 +164,12 @@ where { type Output = ConcreteRingTensor; fn add(self, other: ConcreteRingTensor) -> Self::Output { - ConcreteRingTensor(self.0 + other.0) + match self.0.broadcast(other.0.dim()) { + Some(self_broadcasted) => { + ConcreteRingTensor::(self_broadcasted.to_owned() + other.0) + } + None => ConcreteRingTensor::(self.0 + other.0), + } } } @@ -175,7 +180,12 @@ where { type Output = ConcreteRingTensor; fn mul(self, other: ConcreteRingTensor) -> Self::Output { - ConcreteRingTensor(self.0.mul(other.0)) + match self.0.broadcast(other.0.dim()) { + Some(self_broadcasted) => { + ConcreteRingTensor::(self_broadcasted.to_owned() * other.0) + } + None => ConcreteRingTensor::(self.0 * other.0), + } } } @@ -186,7 +196,12 @@ where { type Output = ConcreteRingTensor; fn sub(self, other: ConcreteRingTensor) -> Self::Output { - ConcreteRingTensor(self.0.sub(other.0)) + match self.0.broadcast(other.0.dim()) { + Some(self_broadcasted) => { + ConcreteRingTensor::(self_broadcasted.to_owned() - other.0) + } + None => ConcreteRingTensor::(self.0 - other.0), + } } } @@ -397,6 +412,69 @@ mod tests { assert_eq!(out, exp) } + #[test] + fn test_add_broadcasting() { + let x_1_backing: ArrayD = array![2].into_dimensionality::().unwrap(); + let x_1 = Ring64Tensor::from(x_1_backing); + let y_1_backing: ArrayD = array![1, 2].into_dimensionality::().unwrap(); + let y_1 = Ring64Tensor::from(y_1_backing); + let z_1 = x_1.add(y_1); + let z_1_exp_backing: ArrayD = array![3, 4].into_dimensionality::().unwrap(); + let z_1_exp = Ring64Tensor::from(z_1_exp_backing); + let x_2_backing: ArrayD = array![1, 2].into_dimensionality::().unwrap(); + let x_2 = Ring64Tensor::from(x_2_backing); + let y_2_backing: ArrayD = array![2].into_dimensionality::().unwrap(); + let y_2 = Ring64Tensor::from(y_2_backing); + let z_2 = x_2.add(y_2); + let z_2_exp_backing: ArrayD = array![3, 4].into_dimensionality::().unwrap(); + let z_2_exp = Ring64Tensor::from(z_2_exp_backing); + + assert_eq!(z_1, z_1_exp); + assert_eq!(z_2, z_2_exp); + } + + #[test] + fn test_sub_broadcasting() { + let x_1_backing: ArrayD = array![2].into_dimensionality::().unwrap(); + let x_1 = Ring64Tensor::from(x_1_backing); + let y_1_backing: ArrayD = array![1, 2].into_dimensionality::().unwrap(); + let y_1 = Ring64Tensor::from(y_1_backing); + let z_1 = x_1.sub(y_1); + let z_1_exp_backing: ArrayD = array![1, 0].into_dimensionality::().unwrap(); + let z_1_exp = Ring64Tensor::from(z_1_exp_backing); + let x_2_backing: ArrayD = array![1, 2].into_dimensionality::().unwrap(); + let x_2 = Ring64Tensor::from(x_2_backing); + let y_2_backing: ArrayD = array![2].into_dimensionality::().unwrap(); + let y_2 = Ring64Tensor::from(y_2_backing); + let z_2 = x_2.sub(y_2); + let z_2_exp_backing: ArrayD = array![-1, 0].into_dimensionality::().unwrap(); + let z_2_exp = Ring64Tensor::from(z_2_exp_backing); + + assert_eq!(z_1, z_1_exp); + assert_eq!(z_2, z_2_exp); + } + + #[test] + fn test_mul_broadcasting() { + let x_1_backing: ArrayD = array![2].into_dimensionality::().unwrap(); + let x_1 = Ring64Tensor::from(x_1_backing); + let y_1_backing: ArrayD = array![1, 2].into_dimensionality::().unwrap(); + let y_1 = Ring64Tensor::from(y_1_backing); + let z_1 = x_1.mul(y_1); + let z_1_exp_backing: ArrayD = array![2, 4].into_dimensionality::().unwrap(); + let z_1_exp = Ring64Tensor::from(z_1_exp_backing); + let x_2_backing: ArrayD = array![1, 2].into_dimensionality::().unwrap(); + let x_2 = Ring64Tensor::from(x_2_backing); + let y_2_backing: ArrayD = array![2].into_dimensionality::().unwrap(); + let y_2 = Ring64Tensor::from(y_2_backing); + let z_2 = x_2.mul(y_2); + let z_2_exp_backing: ArrayD = array![2, 4].into_dimensionality::().unwrap(); + let z_2_exp = Ring64Tensor::from(z_2_exp_backing); + + assert_eq!(z_1, z_1_exp); + assert_eq!(z_2, z_2_exp); + } + #[test] fn bit_extract() { let shape = Shape(vec![5]); From b983c0a69902a8079ef45d0093a2baf811703a36 Mon Sep 17 00:00:00 2001 From: yanndupis Date: Thu, 1 Jul 2021 18:16:58 -0700 Subject: [PATCH 6/7] Add broadcasting to bit ops --- rust/moose/src/bit.rs | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/rust/moose/src/bit.rs b/rust/moose/src/bit.rs index d3c780496..1df9bc60e 100644 --- a/rust/moose/src/bit.rs +++ b/rust/moose/src/bit.rs @@ -61,14 +61,20 @@ impl From for ArrayD { impl BitXor for BitTensor { type Output = BitTensor; fn bitxor(self, other: Self) -> Self::Output { - BitTensor(self.0 ^ other.0) + match self.0.broadcast(other.0.dim()) { + Some(self_broadcasted) => BitTensor(self_broadcasted.to_owned() ^ other.0), + None => BitTensor(self.0 ^ other.0), + } } } impl BitAnd for BitTensor { type Output = BitTensor; fn bitand(self, other: Self) -> Self::Output { - BitTensor(self.0 & other.0) + match self.0.broadcast(other.0.dim()) { + Some(self_broadcasted) => BitTensor(self_broadcasted.to_owned() & other.0), + None => BitTensor(self.0 & other.0), + } } } @@ -131,4 +137,27 @@ mod tests { BitTensor::fill(&shape, 0) ); } + + #[test] + fn test_bit_ops_broadcasting() { + // test xor + assert_eq!( + BitTensor::fill(&Shape(vec![5]), 0) ^ BitTensor::fill(&Shape(vec![1]), 1), + BitTensor::fill(&Shape(vec![5]), 1) + ); + assert_eq!( + BitTensor::fill(&Shape(vec![1]), 0) ^ BitTensor::fill(&Shape(vec![5]), 1), + BitTensor::fill(&Shape(vec![5]), 1) + ); + + // test and + assert_eq!( + BitTensor::fill(&Shape(vec![5]), 0) & BitTensor::fill(&Shape(vec![1]), 1), + BitTensor::fill(&Shape(vec![5]), 0) + ); + assert_eq!( + BitTensor::fill(&Shape(vec![1]), 0) & BitTensor::fill(&Shape(vec![5]), 1), + BitTensor::fill(&Shape(vec![5]), 0) + ); + } } From 6f54f4012e08feb341a372e757ba13cf683fffb9 Mon Sep 17 00:00:00 2001 From: yanndupis Date: Fri, 2 Jul 2021 10:46:51 -0700 Subject: [PATCH 7/7] remove broadcast for bit and ring binary ops --- rust/moose/src/bit.rs | 33 +---------------- rust/moose/src/ring.rs | 84 ++---------------------------------------- 2 files changed, 5 insertions(+), 112 deletions(-) diff --git a/rust/moose/src/bit.rs b/rust/moose/src/bit.rs index 1df9bc60e..d3c780496 100644 --- a/rust/moose/src/bit.rs +++ b/rust/moose/src/bit.rs @@ -61,20 +61,14 @@ impl From for ArrayD { impl BitXor for BitTensor { type Output = BitTensor; fn bitxor(self, other: Self) -> Self::Output { - match self.0.broadcast(other.0.dim()) { - Some(self_broadcasted) => BitTensor(self_broadcasted.to_owned() ^ other.0), - None => BitTensor(self.0 ^ other.0), - } + BitTensor(self.0 ^ other.0) } } impl BitAnd for BitTensor { type Output = BitTensor; fn bitand(self, other: Self) -> Self::Output { - match self.0.broadcast(other.0.dim()) { - Some(self_broadcasted) => BitTensor(self_broadcasted.to_owned() & other.0), - None => BitTensor(self.0 & other.0), - } + BitTensor(self.0 & other.0) } } @@ -137,27 +131,4 @@ mod tests { BitTensor::fill(&shape, 0) ); } - - #[test] - fn test_bit_ops_broadcasting() { - // test xor - assert_eq!( - BitTensor::fill(&Shape(vec![5]), 0) ^ BitTensor::fill(&Shape(vec![1]), 1), - BitTensor::fill(&Shape(vec![5]), 1) - ); - assert_eq!( - BitTensor::fill(&Shape(vec![1]), 0) ^ BitTensor::fill(&Shape(vec![5]), 1), - BitTensor::fill(&Shape(vec![5]), 1) - ); - - // test and - assert_eq!( - BitTensor::fill(&Shape(vec![5]), 0) & BitTensor::fill(&Shape(vec![1]), 1), - BitTensor::fill(&Shape(vec![5]), 0) - ); - assert_eq!( - BitTensor::fill(&Shape(vec![1]), 0) & BitTensor::fill(&Shape(vec![5]), 1), - BitTensor::fill(&Shape(vec![5]), 0) - ); - } } diff --git a/rust/moose/src/ring.rs b/rust/moose/src/ring.rs index eb167ee45..5a6530e12 100644 --- a/rust/moose/src/ring.rs +++ b/rust/moose/src/ring.rs @@ -164,12 +164,7 @@ where { type Output = ConcreteRingTensor; fn add(self, other: ConcreteRingTensor) -> Self::Output { - match self.0.broadcast(other.0.dim()) { - Some(self_broadcasted) => { - ConcreteRingTensor::(self_broadcasted.to_owned() + other.0) - } - None => ConcreteRingTensor::(self.0 + other.0), - } + ConcreteRingTensor(self.0 + other.0) } } @@ -180,12 +175,7 @@ where { type Output = ConcreteRingTensor; fn mul(self, other: ConcreteRingTensor) -> Self::Output { - match self.0.broadcast(other.0.dim()) { - Some(self_broadcasted) => { - ConcreteRingTensor::(self_broadcasted.to_owned() * other.0) - } - None => ConcreteRingTensor::(self.0 * other.0), - } + ConcreteRingTensor(self.0.mul(other.0)) } } @@ -196,12 +186,7 @@ where { type Output = ConcreteRingTensor; fn sub(self, other: ConcreteRingTensor) -> Self::Output { - match self.0.broadcast(other.0.dim()) { - Some(self_broadcasted) => { - ConcreteRingTensor::(self_broadcasted.to_owned() - other.0) - } - None => ConcreteRingTensor::(self.0 - other.0), - } + ConcreteRingTensor(self.0.sub(other.0)) } } @@ -412,69 +397,6 @@ mod tests { assert_eq!(out, exp) } - #[test] - fn test_add_broadcasting() { - let x_1_backing: ArrayD = array![2].into_dimensionality::().unwrap(); - let x_1 = Ring64Tensor::from(x_1_backing); - let y_1_backing: ArrayD = array![1, 2].into_dimensionality::().unwrap(); - let y_1 = Ring64Tensor::from(y_1_backing); - let z_1 = x_1.add(y_1); - let z_1_exp_backing: ArrayD = array![3, 4].into_dimensionality::().unwrap(); - let z_1_exp = Ring64Tensor::from(z_1_exp_backing); - let x_2_backing: ArrayD = array![1, 2].into_dimensionality::().unwrap(); - let x_2 = Ring64Tensor::from(x_2_backing); - let y_2_backing: ArrayD = array![2].into_dimensionality::().unwrap(); - let y_2 = Ring64Tensor::from(y_2_backing); - let z_2 = x_2.add(y_2); - let z_2_exp_backing: ArrayD = array![3, 4].into_dimensionality::().unwrap(); - let z_2_exp = Ring64Tensor::from(z_2_exp_backing); - - assert_eq!(z_1, z_1_exp); - assert_eq!(z_2, z_2_exp); - } - - #[test] - fn test_sub_broadcasting() { - let x_1_backing: ArrayD = array![2].into_dimensionality::().unwrap(); - let x_1 = Ring64Tensor::from(x_1_backing); - let y_1_backing: ArrayD = array![1, 2].into_dimensionality::().unwrap(); - let y_1 = Ring64Tensor::from(y_1_backing); - let z_1 = x_1.sub(y_1); - let z_1_exp_backing: ArrayD = array![1, 0].into_dimensionality::().unwrap(); - let z_1_exp = Ring64Tensor::from(z_1_exp_backing); - let x_2_backing: ArrayD = array![1, 2].into_dimensionality::().unwrap(); - let x_2 = Ring64Tensor::from(x_2_backing); - let y_2_backing: ArrayD = array![2].into_dimensionality::().unwrap(); - let y_2 = Ring64Tensor::from(y_2_backing); - let z_2 = x_2.sub(y_2); - let z_2_exp_backing: ArrayD = array![-1, 0].into_dimensionality::().unwrap(); - let z_2_exp = Ring64Tensor::from(z_2_exp_backing); - - assert_eq!(z_1, z_1_exp); - assert_eq!(z_2, z_2_exp); - } - - #[test] - fn test_mul_broadcasting() { - let x_1_backing: ArrayD = array![2].into_dimensionality::().unwrap(); - let x_1 = Ring64Tensor::from(x_1_backing); - let y_1_backing: ArrayD = array![1, 2].into_dimensionality::().unwrap(); - let y_1 = Ring64Tensor::from(y_1_backing); - let z_1 = x_1.mul(y_1); - let z_1_exp_backing: ArrayD = array![2, 4].into_dimensionality::().unwrap(); - let z_1_exp = Ring64Tensor::from(z_1_exp_backing); - let x_2_backing: ArrayD = array![1, 2].into_dimensionality::().unwrap(); - let x_2 = Ring64Tensor::from(x_2_backing); - let y_2_backing: ArrayD = array![2].into_dimensionality::().unwrap(); - let y_2 = Ring64Tensor::from(y_2_backing); - let z_2 = x_2.mul(y_2); - let z_2_exp_backing: ArrayD = array![2, 4].into_dimensionality::().unwrap(); - let z_2_exp = Ring64Tensor::from(z_2_exp_backing); - - assert_eq!(z_1, z_1_exp); - assert_eq!(z_2, z_2_exp); - } - #[test] fn bit_extract() { let shape = Shape(vec![5]);