The code below tries to define multiplication in a general way so it would work for types with dimensions (like matrices) but also for normal integers. The main issue that I am facing is that I need to specify a dimension for dimensionless things like integer. See the comments at the bottom statements.
I would like to implement MulLeftDimension for MulLeft and drop the generic argument of the mul_left
method as there is no meaning for the parameter for this implementation, is this somehow possible?
trait MulLeft {
type One;
type Multiplier;
type MultiplicationResult;
fn one() -> Self::One;
fn mul_left_no_dim(self, a: Self::Multiplier) -> Self::MultiplicationResult;
}
impl MulLeft for usize {
type One = usize;
type Multiplier = usize;
type MultiplicationResult = usize;
fn one() -> usize { 1 }
fn mul_left_no_dim(self, a: Self::Multiplier) -> Self::MultiplicationResult {
a * self
}
}
trait MulLeftDimension {
type One;
type Multiplier<const RA: usize>;
type MultiplicationResult<const RA: usize>;
fn one() -> Self::One;
fn mul_left<const RA: usize>(self, a: Self::Multiplier<RA>) -> Self::MultiplicationResult<RA>;
}
impl<T: MulLeft> MulLeftDimension for T {
type Multiplier<const RA: usize> = T::Multiplier;
type MultiplicationResult<const RA: usize> = T::MultiplicationResult;
type One = T::One;
fn one() -> Self::One {
T::one()
}
// I would like to remove this const generic in this implementation as its value is not important
fn mul_left<const RA: usize>(self, a: T::Multiplier) -> T::MultiplicationResult {
self.mul_left_no_dim(a)
}
}
impl<const R: usize, const C: usize> MulLeftDimension
for Matrix<R, C>
{
type One = Matrix<R, R>;
type Multiplier<const RA: usize> = Matrix<RA, R>;
type MultiplicationResult<const RA: usize> = Matrix<RA, C>;
fn one() -> Self::One {
Matrix::<R, R>::one()
}
fn mul_left<const RA: usize>(self, lhs: Self::Multiplier<RA>) -> Self::MultiplicationResult<RA> {
let mut res = Self::MultiplicationResult::<RA>::default();
for r in 0..RA {
for c in 0..C {
for i in 0..R {
res.rows[r][c] += lhs.rows[r][i] * self.rows[i][c];
}
}
}
res
}
}
#[derive(Debug)]
struct Matrix<const R: usize, const C: usize> {
rows: [[usize; C]; R],
}
impl<const A: usize> Matrix<A, A> {
fn one() -> Self {
let mut s = Self::default();
for r in 0..A {
s.rows[r][r] = 1;
}
s
}
}
impl<const A: usize, const B: usize> std::default::Default for Matrix<A, B> {
fn default() -> Self {
Self { rows: [[0; B]; A] }
}
}
impl<const A: usize, const B: usize, const C: usize> std::ops::Mul<Matrix<B, C>> for Matrix<A, B> {
type Output = Matrix<A, C>;
fn mul(self, rhs: Matrix<B, C>) -> Self::Output {
rhs.mul_left(self)
}
}
fn main() {
let m1: Matrix<1, 2> = Matrix {
rows: [
[5, 7],
]
};
let m2: Matrix<2, 3> = Matrix {
rows: [
[1,1,1],
[1,1,1],
]
};
let m3 = m1 * m2;
println!("{:?}", m3);
let m3 = m3.mul_left(Matrix::<1, 3>::one());
println!("{:?}", m3);
let number = 5.mul_left::<1>(10); // need to specify an unused value for RA
println!("{:?}", number);
// This fails: 'cannot infer the value of the const parameter `RA` declared on the method `mul_left`'
let number = 5.mul_left(10); // need to specify an unused value for RA
println!("{:?}", number);
}
Errors:
Compiling playground v0.0.1 (/playground)
error[E0282]: type annotations needed
--> src/main.rs:125:20
|
125 | let number = 5.mul_left(10); // need to specify an unused value for RA
| ^^^^^^^^ cannot infer the value of the const parameter `RA` declared on the method `mul_left`
|
help: consider specifying the generic argument
|
125 | let number = 5.mul_left::<RA>(10); // need to specify an unused value for RA
| ++++++
For more information about this error, try `rustc --explain E0282`.
error: could not compile `playground` (bin "playground") due to previous error