Impl Multiplication for Vec

I've the below function:

type OryxResult<T> = std::result::Result<T, Box<dyn std::error::Error>>;
fn foo(x: &[&Vec<f64>], y: &[&Vec<f64>]) -> OryxResult<Vec<f64>> {
    // n x m * m x p = n x p
    let m = x.len();   // 2 // number of vecs
    let n = x[0].len();  // 3 // vec length

    let _m = y[0].len();   // 2  // vec length
    let p = y.len();  // 1 // number of vecs
    if x.len() != y[0].len() {
        Err(format!("cross dimentional is invalid"))?
    } else {
        //let mut array: Vec<Vec<i32>> = vec![vec![Default::default(); p]; n];
        let mut array: Vec<f64> = vec![Default::default(); n];

        for i in 0..n {  // 3;
            for j in 0..m {   // 2
                for k in 0..p {   // 1
                //    array[i][k] += x[j][i] * y[k][j];
                    array[i] += x[j][i] * y[k][j];
                }
            }
        }
        Ok(array)
    }
}

That is called using example below:

fn main() {
    let apple_pie = vec![1., 0., 0.];
    let burger = vec![0., 1., 0.];
    let chekin = vec![0., 0., 1.];
    let food: [&Vec<f64>; 2] = [&apple_pie, &burger];
    let all_food: [&Vec<f64>; 3] = [&apple_pie, &burger, &chekin];    

    let sunny = vec![1., 0.];
    let rainy = vec![0., 1.];
    let weather: [&Vec<f64>; 1] = [&rainy];

    match foo(&food, &weather) {
        Err(e) => println!("Error = {:?}", e),
        Ok(r) => {
             match all_food.iter().position(|&v| *v == r) {
                 None => println!("Not found"),
                 Some(i) => match i {
                     0 => println!("Apple Pie"),
                     1 => println!("Chekin"),
                     2 => println!("Burger"),
                     _ => println!("check again"),
                 }
             }
        }
    } ;
}

Which is working fine.

I'm looking for making it an extension, something below, but I stucked:

use std::ops::Mul;
type OryxResult<T> = std::result::Result<T, Box<dyn std::error::Error>>;

impl Mul<Vec<f64>> Vec<f64> {
    type Output = Self;

    fn mul(self, rhs: Vec<f64>) ->  OryxResult<Vec<f64>> {
       ...
    }
}

There are two main issues there:

  1. This implementetion is prohibited by the orphan rules, since neither the trait nor the type is yours. In this cases, multiplication should be implemented for the custom wrapper.
  2. Multiplication can (technically) be fallible, but this must be reflected in the associated type - type Output: OryxResult<Self>. However, AFAIK this is bad taste: operations which can result in error usually go into different functions (think f64::checked_mul and friends), and ordinary operations usually contain either a debug_assert! or an explicit panic! in the case of wrong inputs.

I tried the below:

use std::ops::Mul;

#[derive(Debug, PartialEq)]
struct Layer { value: Vec<Vec<f64>> }

#[derive(Debug, PartialEq)]
struct Vector { value: Vec<Vec<f64>> }

impl Layer {
    fn vecs_len(&self) -> &usize {
        &self.value[0].len()
    }

    fn vecs_num(&self) -> &usize {
        &self.value.len()
    }
}

impl Vector {
    fn vecs_len(&self) -> &usize {
        &self.value[0].len()
    }

    fn vecs_num(&self) -> &usize {
        &self.value.len()
    }
}

// 3 x 2 * 2 x 1 = 3 x 1
impl Mul<Layer> for Vector {
    type Output = OryxResult<Self>;

    fn mul(self, rhs: Layer) -> Self::Output {
        let m = *self.vecs_num();   // 2 // number of vecs
        let n = *self.vecs_len();  // 3 // vec length

        let _m = *rhs.vecs_len();   // 2  // vec length
        let p = *rhs.vecs_num();

        if self.vecs_num() != rhs.vecs_len() {
            Err(format!("cross dimentional is invalid"))?
        } else {
            let mut array: Vector; // = vec![vec![Default::default(); p]; n];
            //let mut array: Vec<f64> = vec![Default::default(); n];

            for i in 0..n {  // 3;
                for j in 0..m {   // 2
                    for k in 0..p {   // 1
                        array[i][k] += slef[j][i] * rhs[k][j];
                    //    array[i] += self[j][i] * rhs[k][j];
                    }
                }
            }
            Ok(array)
        }
    }
}

But got the below errors:

error[E0425]: cannot find value `slef` in this scope
  --> src\main.rs:49:40
   |
49 |                         array[i][k] += slef[j][i] * rhs[k][j];
   |                                        ^^^^ not found in this scope

error[E0608]: cannot index into a value of type `Vector`
  --> src\main.rs:49:25
   |
49 |                         array[i][k] += slef[j][i] * rhs[k][j];
   |                         ^^^^^^^^

error[E0608]: cannot index into a value of type `Layer`
  --> src\main.rs:49:53
   |
49 |                         array[i][k] += slef[j][i] * rhs[k][j];
   |                                                     ^^^^^^

error: aborting due to 3 previous errors

You have a typo on that line - slef should be self.

Since you're now using a wrapper type, you can't directly index - you either need to do array.value[i][k] or implement Index/IndexMut for your wrappers.

1 Like

You need to wrap vec into your own custom type if you really want to do this. Implement deref as well:

use std::ops::Deref;
use std::ops::Mul;

struct MyVec {
    inner: Vec<usize>
}

impl Deref for MyVec {
    type Target = Vec<usize>;
    
    fn deref(&self) -> &Self::Target {
        &self.inner
    }
}

impl Mul for MyVec {
    type Output = Vec<usize>;
    
    fn mul(self, rhs: Self) -> Self::Output {
        assert_eq!(self.len(), rhs.len());
        let mut new_vec = Vec::with_capacity(self.len());
        new_vec.resize(self.len(), 0); // resize with zeroes
        
        for i in 0..self.len() {
            new_vec[i] = &self[i] * &rhs[i];
        }
        
        new_vec
    }
} 

@Cerber-Ursi didn't mean to tag you :slight_smile:

Thanks, it worked with me now as:

use std::ops::Mul;

#[derive(Debug, PartialEq)]
struct Layer { value: Vec<Vec<f64>> }

#[derive(Debug, PartialEq)]
struct Vector { value: Vec<Vec<f64>> }

impl Layer {
    fn vecs_len(&self) -> usize {
        self.value[0].len()
    }

    fn vecs_num(&self) -> usize {
        self.value.len()
    }
}

impl Vector {
    fn vecs_len(&self) -> usize {
        self.value[0].len()
    }

    fn vecs_num(&self) -> usize {
        self.value.len()
    }
}

impl Mul<Layer> for Vector {
    type Output = OryxResult<Self>;

    fn mul(self, rhs: Layer) -> Self::Output {
        let m = self.vecs_num();
        let n = self.vecs_len();

        let _m = rhs.vecs_len();
        let p = rhs.vecs_num();

        if self.vecs_num() != rhs.vecs_len() {
            Err(format!("cross dimentional is invalid"))?
        } else {
            let mut array: Vector = Vector {value: vec![vec![Default::default(); p]; n] }; // vec![Vec::new()]};

            for i in 0..n {
                for j in 0..m {
                    for k in 0..p {
                    array.value[i][k]  += self.value[j][i] * rhs.value[k][j]; //array[i][k] += self[j][i] * rhs[k][j];
                    }
                }
            }
            Ok(array)
        }
    }
}

And called as:

fn main() {
    let sunny = vec![1., 0.];
    let rainy = vec![0., 1.];
    let layer: Layer = Layer {value: vec![rainy]};

    let apple_pie = vec![1., 0., 0.];
    let burger = vec![0., 1., 0.];
    let vector: Vector = Vector {value: vec![apple_pie, burger]};

    let check = (vector * layer).unwrap().value;
    println!("{:?}", check);
}

Thanks, I'' check your methodology and update you.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.