How to define a function in Rust? - rust

I decided to do 2D vector cross product in Rust. In JavaScript, this is simple to do:
float CrossProduct( const Vec2& a, const Vec2& b ) {
return a.x * b.y - a.y * b.x;
}
I tried to convert it to the Rust system:
// Just created two separate variables for the two different vectors
let vec1 = vec![1.15, 7.0];
let vec2 = vec![7.0, 2.0];
let cross_product(&vec1, &vec2) = vec1[0] * vec2[1] - vec1[1] * vec2[0];
println!("{}", cross_product);
// I also tried return.
let vec1 = vec![1.15, 7.0];
let vec2 = vec![7.0, 2.0];
let cross_product(&vec1, &vec2) {
return (vec1[0] * vec2[1] - vec1[1] * vec2[0]);
}
println!("{}", cross_product);
I thought that one of these would work, however this was more of a reality check to me how different Rust can be from any language I have used previously.
I found a very inefficient way to work around this, however I would rather learn to do this correctly. I am new to Rust, so please take my attempts with a grain of salt.

There are two possible ways to do this.
First Way
You can declare a function and pass it into println!() which is similar to many programming languages like Java, C#, etc.
// Declare the function
fn cross_product(slice1: &[i32], slice2: &[i32]) -> i32 {
slice1[0] * slice2[1] - slice1[1] * slice2[2]
}
// Use it Like following
fn main() {
let vec1 = vec![1, 2, 3];
let vec2 = vec![4, 5, 6];
println!("{}", cross_product(&vec1[..], &vec2[..]));
}
Second Way
You can declare a closure and pass it into println!(), a common methodology in functional programming:
// You can declare a closure and use it as function in the same code block
fn main() {
let vec1 = vec![1, 2, 3];
let vec2 = vec![4, 5, 6];
let cross_product = |slice1: &[i32], slice2: &[i32]| -> i32 {
let result = slice1[0] * slice2[1] - slice1[1] * slice2[2];
result
};
println!("{}", cross_product(&vec1[..], &vec2[..]));
}
Please note that I have created the vectors and closures using the i32 data type, which corresponds to an integer. You can change the type with f32 or if you want wider float range f64.

It looks like you are mainly having problems with Rust syntax. You can either create a cross product function or do the cross product inline.
let vec1 = vec![1.15, 7.0];
let vec2 = vec![7.0, 2.0];
let cross_product = vec1[0] * vec2[1] - vec1[1] * vec2[0];
println!("{}", cross_product);
If you want a function you can use continually.
fn function_cross_product(vec1: Vec<f64>, vec2: Vec<f64>) -> f64 {
return vec1[0] * vec2[1] - vec1[1] * vec2[0];
};
let other_product = function_cross_product(vec1, vec2);
println!("{}", other_product);
The second solution can be misleading because it will always produce the cross product for a 2x2 vector even if you pass different sized vectors.

Related

How to let several threads write to the same variable without mutex in Rust?

I am trying to implement an outer function that could calculate the outer product of two 1D arrays. Something like this:
use std::thread;
use ndarray::prelude::*;
pub fn multithread_outer(A: &Array1<f64>, B: &Array1<f64>) -> Array2<f64> {
let mut result = Array2::<f64>::default((A.len(), B.len()));
let thread_num = 5;
let n = A.len() / thread_num;
// a & b are ArcArray2<f64>
let a = A.to_owned().into_shared();
let b = B.to_owned().into_shared();
for i in 0..thread_num{
let a = a.clone();
let b = b.clone();
thread::spawn(move || {
for j in i * n..(i + 1) * n {
for k in 0..b.len() {
// This is the line I want to change
result[[j, k]] = a[j] * b[k];
}
}
});
}
// Use join to make sure all threads finish here
// Not so related to this question, so I didn't put it here
result
}
You can see that by design, two threads will never write to the same element. However, rust compiler will not allow two mutable references to the same result variable. And using mutex will make this much slower. What is the right way to implement this function?
While it is possible to do manually (with thread::scope and split_at_mut, for example), ndarray already has parallel iteration integrated into its library, based on rayon:
https://docs.rs/ndarray/latest/ndarray/parallel
Here is how your code would look like with parallel iterators:
use ndarray::parallel::prelude::*;
use ndarray::prelude::*;
pub fn multithread_outer(a: &Array1<f64>, b: &Array1<f64>) -> Array2<f64> {
let mut result = Array2::<f64>::default((a.len(), b.len()));
result
.axis_iter_mut(Axis(0))
.into_par_iter()
.enumerate()
.for_each(|(row_id, mut row)| {
for (col_id, cell) in row.iter_mut().enumerate() {
*cell = a[row_id] * b[col_id];
}
});
result
}
fn main() {
let a = Array1::from_vec(vec![1., 2., 3.]);
let b = Array1::from_vec(vec![4., 5., 6., 7.]);
let c = multithread_outer(&a, &b);
println!("{}", c)
}
[[4, 5, 6, 7],
[8, 10, 12, 14],
[12, 15, 18, 21]]

Accessing Vector elements gives me an error Rust

I trying to write a program that will find the median of any given list.
Eventually, In the FINAL FINAL stretch, an error was shot into my face.
I tried to access elements of a Vector through a variable.
Take a look at the calc_med() function.
use std::io;
use std::sync::Mutex;
#[macro_use]
extern crate lazy_static;
lazy_static! {
static ref num_list: Mutex<Vec<f64>> = Mutex::new(Vec::new());
}
fn main() {
loop {
println!("Enter: ");
let mut inp: String = String::new();
io::stdin().read_line(&mut inp).expect("Failure");
let upd_inp: f64 = match inp.trim().parse() {
Ok(num) => num,
Err(_) => {
if inp.trim() == String::from("q") {
break;
} else if inp.trim() == String::from("d") {
break {
println!("Done!");
calc_med();
};
} else {
continue;
}
}
};
num_list.lock().unwrap().push(upd_inp);
num_list
.lock()
.unwrap()
.sort_by(|a, b| a.partial_cmp(b).unwrap());
println!("{:?}", num_list.lock().unwrap());
}
}
fn calc_med() {
// FOR THE ATTENTION OF STACKOVERFLOW
let n: f64 = ((num_list.lock().unwrap().len()) as f64 + 1.0) / 2.0;
if n.fract() == 0.0 {
let n2: usize = n as usize;
} else {
let n3: u64 = n.round() as u64;
let n4: usize = n3 as usize;
let median: f64 = (num_list[n4] + num_list[n4 - 1]) / 2;
println!("{}", median);
}
}
The error is as following:
Compiling FindTheMedian v0.1.0 (/home/isaak/Documents/Code/Rusty/FindTheMedian)
error[E0608]: cannot index into a value of type `num_list`
--> src/main.rs:50:28
|
50 | let median: f64 = (num_list[n4] + num_list[n4 - 1]) / 2;
| ^^^^^^^^^^^^
error[E0608]: cannot index into a value of type `num_list`
--> src/main.rs:50:43
|
50 | let median: f64 = (num_list[n4] + num_list[n4 - 1]) / 2;
| ^^^^^^^^^^^^^^^^
The current code is trying to index a variable of type Mutex<Vec<f64>>, which is not valid. The way you access the underlying data in a mutex is by calling .lock() on it, which will in turn return a structure that resembles Result<Vec<f64>, Error>.
So, fixing only the line would look like this:
let num_list_vec = num_list.lock().unwrap();
let median: f64 = (num_list_vec[n4] + num_list_vec[n4 - 1]) / 2;
However, since you already locked at the start of the function this will not work, since the mutex is already locked. The best way then is to do the locking + unwraping at the start of the function and use the underlying value in all places:
fn calc_med() {
let num_list_vec = num_list.lock().unwrap();
let n: f64 = ((num_list_vec.len()) as f64 + 1.0) / 2.0;
if n.fract() == 0.0 {
let n2: usize = n as usize;
} else {
let n3: u64 = n.round() as u64;
let n4: usize = n3 as usize;
let median: f64 = (num_list_vec[n4] + num_list_vec[n4 - 1]) / 2;
println!("{}", median);
}
}
Edit: Checking your main, I see you are also lock().unwrap()ing in sequence a lot, which is not the way Mutex should be used. Mutex is mainly used whenever you have a need for multi-threaded programming, so that different threads cannot access the same variable twice. It also incurs a performance hit, so you shouldn't really use it in single-threaded scenarios most of the time.
Unless there's a bigger picture we're missing, you should just define your Vec in main and pass it to calc_med as an argument. If the reason you did what you did was to get it as a global, there are other ways to do that in Rust without performance hits, but due to safe design of Rust these ways are not encouraged and should only be used if you know 100% what you want.
Your error is the num_list is not an vector, it's a mutex with an vector inside of it. To access the value inside of a mutex, you must lock it, and then unwrap the result. You do this correctly in main.
To avoid continually unlocking and locking, it is generally best practice to lock the mutex once, at the start of the function. Rust will automatically drop the lock when the reference goes out of scope. See the updated example:
fn calc_med() { // FOR THE ATTENTION OF STACKOVERFLOW
let nums = num_list.lock().unwrap();
let n: f64 = (nums.len() as f64 + 1.0) / 2.0;
if n.fract() == 0.0 {
let n2: usize = n as usize;
} else {
let n3: u64 = n.round() as u64;
let n4: usize = n3 as usize;
let median: f64 = (nums[n4] + nums[n4 - 1]) / 2;
println!("{}", median);
}
}

Closure with Box<T> arguments in Rust

I want to know how to code Closure(function) with Box argument in Rust.
For just , it's simple.
fn main() {
let a = 5;
let double = |x| 2 * x;
let b = double(a); //10
}
now, for Box
fn main() {
let a = Box::new(5);
let double = |x| 2 * x; //how to write?
let b = double(a);
}
I don't know what is the adequate or smart way to code, and for unknown reason, the official document or Google did not help.
Please advise.
Here is an example how you can do that:
fn main() {
let a = Box::new(5);
let double = |x: Box<i32>| 2 * *x;
let b = double(a);
print!("{b}")
}
First, you need to specify the closure parameter type in this case. Instead of Box<i32>, you can also write Box<_>.
Next, you need to get the value owned by the Box via *x.

Proptest: Strategy to generate vectors of vectors

I want to generate DAGs with proptest. The algorithm that I pick would be this. I've written the plain algorithm below -- but I need help transforming this to a proptest strategy.
What would a strategy need to look like that did the same as the below code but without using a random number generator? (It goes without saying that random number generators are bad for property-based testing.)
Standard code without proptest strategy:
(https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=2de4a757a96d123bf83b5157e0633d33)
use rand::Rng;
fn main() {
println!("{:?}", random_vec_of_vec());
}
fn random_vec_of_vec() -> Vec<Vec<u16>> {
const N: u16 = 30;
const K: usize = 3;
let mut rng = rand::thread_rng();
let length: u16 = rng.gen_range(0, N);
let mut outer = vec![];
for index in 1..length {
let mut inner = vec![0u16; rng.gen_range(0, K)];
for e in &mut inner {
*e = rng.gen_range(0, index);
}
// De-duplicate elements. Particularly a problem with `index < K`.
inner.sort();
inner.dedup();
outer.push(inner);
}
outer
}
Previous work
I tried using the vec function, but I would need to nest two vec functions. And, the inner vec function could only generate values up to the index in the outer vector.
use proptest::collection::vec;
// INDEX should be the value of the position of the inner vector
// in the outer vector. How could the be found?
let strategy = vec(vec(1..INDEX, 0..K), 0..N);
The index method is not helpful because the right size would still not be known.
One way to go about this, is to replace each rng.gen_range() call with a strategy. Nested strategies must then be connected with prop_flat_map.
In the below code, I replaced my pattern
let length = rng.gen_range(0, N); for i in 1..length { .. }, with a new function vec_from_length(length: usize), which returns a Strategy.
#[cfg(test)]
mod tests {
use super::*;
use proptest::collection::hash_set;
use proptest::prelude::*;
use std::collections::HashSet;
proptest! {
#[test]
fn meaningless_test(v in vec_of_vec()) {
let s = sum(&v); // sum of the sum of all vectors.
prop_assert!(s < 15);
}
}
fn vec_of_vec() -> impl Strategy<Value = Vec<Vec<u16>>> {
const N: u16 = 10;
let length = 0..N;
length.prop_flat_map(vec_from_length).prop_map(convert)
}
fn vec_from_length(length: u16) -> impl Strategy<Value = Vec<HashSet<u16>>> {
const K: usize = 5;
let mut result = vec![];
for index in 1..length {
// Using a hash_set instead of vec because the elements should be unique.
let inner = hash_set(0..index, 0..K);
result.push(inner);
}
result
}
/// Convert Vec<HashSet<T>> to Vec<Vec<T>>
fn convert(input: Vec<HashSet<u16>>) -> Vec<Vec<u16>> {
let mut output = vec![];
for inner in input {
output.push(inner.into_iter().collect())
}
output
}
}
One more thing: An impl Strategy<Value=Vec<T>> can be generated from either the vec function (a strategy of vector) or from a vector of strategies! In the above code, I do this through having result be pushed with hash_set(..) which is a Strategy. The type is thus something like Vec<Strategy<T>> not Strategy<Vec<T>> (pedantic: Strategy is not a type, maybe).

Is it necessary to cast to float to access basic math functions in Rust?

fn main() {
let a = 1i32;
let b = 2i32;
let smallest = (a as f64).min((b as f64)) as i32;
println!("{}", smallest);
}
Is all the casting to and from floats really necessary?
The function you're looking for is ::std::cmp::min, which works on any type that implements Ord:
fn main() {
let a = 1i32;
let b = 2i32;
let smallest = ::std::cmp::min(a, b);
println!("{}", smallest);
}
You were using the min method from f64 (an equivalent exists for f32).
No. As a quick search of the API reference reveals, you can just use std::cmp::min:
use std::cmp::min;
fn main() {
let a = 1i32;
let b = 2i32;
let smallest = min(a, b);
println!("{}", smallest);
}
min being declared specially on f32 and f64 is because floating point types do not implement Ord. Due to the presence of NaN, they only have partial ordering (PartialOrd) whilst std::cmp::min requires a total ordering (Ord).

Resources