From 20099616bfb3c45709d6510d9892d9d7a8a0b6e5 Mon Sep 17 00:00:00 2001 From: Dorival Pedroso Date: Wed, 29 May 2024 11:20:32 +1000 Subject: [PATCH 1/7] [tensor] Use slice in Tensor2 set_mandel_vector --- russell_tensor/src/tensor2.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/russell_tensor/src/tensor2.rs b/russell_tensor/src/tensor2.rs index 77c1dae0..24d1b39b 100644 --- a/russell_tensor/src/tensor2.rs +++ b/russell_tensor/src/tensor2.rs @@ -879,7 +879,7 @@ impl Tensor2 { /// -4.0 / SQRT_2, /// ]); /// - /// a.set_mandel_vector(2.0, &v_mandel); + /// a.set_mandel_vector(2.0, v_mandel.as_data()); /// /// assert_eq!( /// format!("{:.1}", a.as_matrix()), @@ -892,8 +892,8 @@ impl Tensor2 { /// Ok(()) /// } /// ``` - pub fn set_mandel_vector(&mut self, alpha: f64, other: &Vector) { - assert_eq!(self.mandel.dim(), other.dim()); + pub fn set_mandel_vector(&mut self, alpha: f64, other: &[f64]) { + assert_eq!(self.mandel.dim(), other.len()); let dim = self.vec.dim(); self.vec[0] = alpha * other[0]; self.vec[1] = alpha * other[1]; @@ -2648,7 +2648,7 @@ mod tests { fn set_mandel_vector_panics_panics_on_incorrect_input() { let mut a = Tensor2::new(Mandel::Symmetric2D); let b = Vector::new(1); - a.set_mandel_vector(2.0, &b); + a.set_mandel_vector(2.0, b.as_data()); } #[test] @@ -2659,7 +2659,7 @@ mod tests { tt.vec.fill(NOISE); tt.set_mandel_vector( 2.0, - &Vector::from(&[ + &[ 1.0, 5.0, 9.0, @@ -2669,7 +2669,7 @@ mod tests { -2.0 / SQRT_2, -2.0 / SQRT_2, -4.0 / SQRT_2, - ]), + ], ); let correct = &[[2.0, 4.0, 6.0], [8.0, 10.0, 12.0], [14.0, 16.0, 18.0]]; mat_approx_eq(&tt.as_matrix(), correct, 1e-14); @@ -2679,7 +2679,7 @@ mod tests { tt.vec.fill(NOISE); tt.set_mandel_vector( 2.0, - &Vector::from(&[1.0, 2.0, 3.0, 4.0 * SQRT_2, 5.0 * SQRT_2, 6.0 * SQRT_2]), + &[1.0, 2.0, 3.0, 4.0 * SQRT_2, 5.0 * SQRT_2, 6.0 * SQRT_2], ); let correct = &[[2.0, 8.0, 12.0], [8.0, 4.0, 10.0], [12.0, 10.0, 6.0]]; mat_approx_eq(&tt.as_matrix(), correct, 1e-14); @@ -2687,7 +2687,7 @@ mod tests { // symmetric 2D let mut tt = Tensor2::new(Mandel::Symmetric2D); tt.vec.fill(NOISE); - tt.set_mandel_vector(2.0, &Vector::from(&[1.0, 2.0, 3.0, 4.0 * SQRT_2])); + tt.set_mandel_vector(2.0, &[1.0, 2.0, 3.0, 4.0 * SQRT_2]); let correct = &[[2.0, 8.0, 0.0], [8.0, 4.0, 0.0], [0.0, 0.0, 6.0]]; mat_approx_eq(&tt.as_matrix(), correct, 1e-14); } From 9b0b72e01ffcefbb8b60ada1f71c9b0849de6b7e Mon Sep 17 00:00:00 2001 From: Dorival Pedroso Date: Wed, 29 May 2024 11:28:47 +1000 Subject: [PATCH 2/7] [lab] Impl set_vector method of NumVector --- russell_lab/src/vector/num_vector.rs | 37 ++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/russell_lab/src/vector/num_vector.rs b/russell_lab/src/vector/num_vector.rs index 321f86e2..c6997c1b 100644 --- a/russell_lab/src/vector/num_vector.rs +++ b/russell_lab/src/vector/num_vector.rs @@ -428,6 +428,29 @@ where self.data[i] = value; } + /// Copy another vector into this one + /// + /// # Examples + /// + /// ``` + /// # use russell_lab::NumVector; + /// let mut u = NumVector::::from(&[1.0, 2.0]); + /// u.set_vector(&[-3.0, -4.0]); + /// let correct = "┌ ┐\n\ + /// │ -3 │\n\ + /// │ -4 │\n\ + /// └ ┘"; + /// assert_eq!(format!("{}", u), correct); + /// ``` + /// + /// # Panics + /// + /// This function may panic if the other vector has a different length than this one + pub fn set_vector(&mut self, other: &[T]) { + assert_eq!(other.len(), self.data.len()); + self.data.copy_from_slice(other); + } + /// Applies a function over all components of this vector /// /// ```text @@ -887,6 +910,20 @@ mod tests { assert_eq!(u.data, &[-1.0, -2.0]); } + #[test] + #[should_panic] + fn set_vector_panics_on_wrong_len() { + let mut u = NumVector::::from(&[1.0, 2.0]); + u.set_vector(&[8.0, 9.0, 10.0]); + } + + #[test] + fn set_vector_works() { + let mut u = NumVector::::from(&[1.0, 2.0]); + u.set_vector(&[8.0, 9.0]); + assert_eq!(u.data, &[8.0, 9.0]); + } + #[test] fn map_works() { let mut u = NumVector::::from(&[-1.0, -2.0, -3.0]); From ce7546e9cb7cfe61645b8db277e4be5977d81961 Mon Sep 17 00:00:00 2001 From: Dorival Pedroso Date: Wed, 29 May 2024 17:46:13 +1000 Subject: [PATCH 3/7] [lab] Implement scale method of NumVector --- russell_lab/src/vector/num_vector.rs | 47 ++++++++++++++++++++++------ 1 file changed, 37 insertions(+), 10 deletions(-) diff --git a/russell_lab/src/vector/num_vector.rs b/russell_lab/src/vector/num_vector.rs index c6997c1b..f0de8323 100644 --- a/russell_lab/src/vector/num_vector.rs +++ b/russell_lab/src/vector/num_vector.rs @@ -4,7 +4,7 @@ use serde::de::DeserializeOwned; use serde::{Deserialize, Serialize}; use std::cmp; use std::fmt::{self, Write}; -use std::ops::{Index, IndexMut}; +use std::ops::{Index, IndexMut, MulAssign}; /// Implements a vector with numeric components for linear algebra /// @@ -90,7 +90,7 @@ use std::ops::{Index, IndexMut}; #[derive(Clone, Debug, Deserialize, Serialize)] pub struct NumVector where - T: Num + NumCast + Copy + DeserializeOwned + Serialize, + T: MulAssign + Num + NumCast + Copy + DeserializeOwned + Serialize, { #[serde(bound(deserialize = "Vec: Deserialize<'de>"))] data: Vec, @@ -98,7 +98,7 @@ where impl NumVector where - T: Num + NumCast + Copy + DeserializeOwned + Serialize, + T: MulAssign + Num + NumCast + Copy + DeserializeOwned + Serialize, { /// Creates a new (zeroed) vector /// @@ -451,6 +451,26 @@ where self.data.copy_from_slice(other); } + /// Scales this vector + /// + /// # Examples + /// + /// ``` + /// # use russell_lab::NumVector; + /// let mut u = NumVector::::from(&[1.0, 2.0]); + /// u.scale(2.0); + /// let correct = "┌ ┐\n\ + /// │ 2 │\n\ + /// │ 4 │\n\ + /// └ ┘"; + /// assert_eq!(format!("{}", u), correct); + /// ``` + pub fn scale(&mut self, alpha: T) { + for i in 0..self.data.len() { + self.data[i] *= alpha; + } + } + /// Applies a function over all components of this vector /// /// ```text @@ -547,7 +567,7 @@ where impl fmt::Display for NumVector where - T: Num + NumCast + Copy + DeserializeOwned + Serialize + fmt::Display, + T: MulAssign + Num + NumCast + Copy + DeserializeOwned + Serialize + fmt::Display, { /// Generates a string representation of the NumVector /// @@ -622,7 +642,7 @@ where /// The index function may panic if the index is out-of-bounds. impl Index for NumVector where - T: Num + NumCast + Copy + DeserializeOwned + Serialize, + T: MulAssign + Num + NumCast + Copy + DeserializeOwned + Serialize, { type Output = T; #[inline] @@ -651,7 +671,7 @@ where /// The index function may panic if the index is out-of-bounds. impl IndexMut for NumVector where - T: Num + NumCast + Copy + DeserializeOwned + Serialize, + T: MulAssign + Num + NumCast + Copy + DeserializeOwned + Serialize, { #[inline] fn index_mut(&mut self, index: usize) -> &mut Self::Output { @@ -672,7 +692,7 @@ where /// ``` impl IntoIterator for NumVector where - T: Num + NumCast + Copy + DeserializeOwned + Serialize, + T: MulAssign + Num + NumCast + Copy + DeserializeOwned + Serialize, { type Item = T; type IntoIter = std::vec::IntoIter; @@ -696,7 +716,7 @@ where /// ``` impl<'a, T> IntoIterator for &'a NumVector where - T: Num + NumCast + Copy + DeserializeOwned + Serialize, + T: MulAssign + Num + NumCast + Copy + DeserializeOwned + Serialize, { type Item = &'a T; type IntoIter = std::slice::Iter<'a, T>; @@ -721,7 +741,7 @@ where /// ``` impl<'a, T> IntoIterator for &'a mut NumVector where - T: Num + NumCast + Copy + DeserializeOwned + Serialize, + T: MulAssign + Num + NumCast + Copy + DeserializeOwned + Serialize, { type Item = &'a mut T; type IntoIter = std::slice::IterMut<'a, T>; @@ -733,7 +753,7 @@ where /// Allows accessing NumVector as an Array1D impl<'a, T: 'a> AsArray1D<'a, T> for NumVector where - T: Num + NumCast + Copy + DeserializeOwned + Serialize, + T: MulAssign + Num + NumCast + Copy + DeserializeOwned + Serialize, { #[inline] fn size(&self) -> usize { @@ -924,6 +944,13 @@ mod tests { assert_eq!(u.data, &[8.0, 9.0]); } + #[test] + fn scale_works() { + let mut u = NumVector::::from(&[2.0, 4.0]); + u.scale(0.5); + assert_eq!(u.data, &[1.0, 2.0]); + } + #[test] fn map_works() { let mut u = NumVector::::from(&[-1.0, -2.0, -3.0]); From 5b78d628875a7507aae9e6e3dfbaa420f3049e45 Mon Sep 17 00:00:00 2001 From: Dorival Pedroso Date: Wed, 29 May 2024 17:46:58 +1000 Subject: [PATCH 4/7] [lab] Add doc comment --- russell_lab/src/vector/num_vector.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/russell_lab/src/vector/num_vector.rs b/russell_lab/src/vector/num_vector.rs index f0de8323..b9bc6717 100644 --- a/russell_lab/src/vector/num_vector.rs +++ b/russell_lab/src/vector/num_vector.rs @@ -453,6 +453,10 @@ where /// Scales this vector /// + /// ```text + /// u := alpha * u + /// ``` + /// /// # Examples /// /// ``` From 75bdd779d67c8607b6c8a476b5bd43efb1389bac Mon Sep 17 00:00:00 2001 From: Dorival Pedroso Date: Thu, 30 May 2024 10:45:31 +1000 Subject: [PATCH 5/7] [lab] Impl split2 and join2 methods of NumVector --- russell_lab/src/vector/num_vector.rs | 134 +++++++++++++++++++++++---- 1 file changed, 114 insertions(+), 20 deletions(-) diff --git a/russell_lab/src/vector/num_vector.rs b/russell_lab/src/vector/num_vector.rs index b9bc6717..87b630c9 100644 --- a/russell_lab/src/vector/num_vector.rs +++ b/russell_lab/src/vector/num_vector.rs @@ -387,6 +387,10 @@ where /// Returns the i-th component /// + /// # Panics + /// + /// This function may panic if the index is out-of-bounds. + /// /// # Examples /// /// ``` @@ -394,10 +398,6 @@ where /// let u = NumVector::::from(&[1.0, 2.0]); /// assert_eq!(u.get(1), 2.0); /// ``` - /// - /// # Panics - /// - /// This function may panic if the index is out-of-bounds. #[inline] pub fn get(&self, i: usize) -> T { assert!(i < self.data.len()); @@ -406,6 +406,10 @@ where /// Change the i-th component /// + /// # Panics + /// + /// This function may panic if the index is out-of-bounds. + /// /// # Examples /// /// ``` @@ -418,10 +422,6 @@ where /// └ ┘"; /// assert_eq!(format!("{}", u), correct); /// ``` - /// - /// # Panics - /// - /// This function may panic if the index is out-of-bounds. #[inline] pub fn set(&mut self, i: usize, value: T) { assert!(i < self.data.len()); @@ -430,6 +430,10 @@ where /// Copy another vector into this one /// + /// # Panics + /// + /// This function may panic if the other vector has a different length than this one + /// /// # Examples /// /// ``` @@ -442,15 +446,68 @@ where /// └ ┘"; /// assert_eq!(format!("{}", u), correct); /// ``` - /// - /// # Panics - /// - /// This function may panic if the other vector has a different length than this one pub fn set_vector(&mut self, other: &[T]) { assert_eq!(other.len(), self.data.len()); self.data.copy_from_slice(other); } + /// Splits this vector into another two vectors + /// + /// **Requirements:** `u.len() + v.len() == self.len()` + /// + /// This function is the opposite of [NumVector::join2()] + /// + /// # Panics + /// + /// This function may panic if the sum of the lengths of u and v are different that this vector's length + /// + /// # Examples + /// + /// ``` + /// # use russell_lab::NumVector; + /// let w = NumVector::::from(&[1.0, 2.0, 3.0]); + /// let mut u = NumVector::::new(2); + /// let mut v = NumVector::::new(1); + /// + /// w.split2(u.as_mut_data(), v.as_mut_data()); + /// + /// assert_eq!(u.as_data(), &[1.0, 2.0]); + /// assert_eq!(v.as_data(), &[3.0]); + /// ``` + pub fn split2(&self, u: &mut [T], v: &mut [T]) { + assert_eq!(u.len() + v.len(), self.data.len()); + u.copy_from_slice(&self.data[..u.len()]); + v.copy_from_slice(&self.data[u.len()..]); + } + + /// Joins two vectors into this one + /// + /// **Requirements:** `u.len() + v.len() == self.len()` + /// + /// This function is the opposite of [NumVector::split2()] + /// + /// # Panics + /// + /// This function may panic if the sum of the lengths of u and v are different that this vector's length + /// + /// # Examples + /// + /// ``` + /// # use russell_lab::NumVector; + /// let mut w = NumVector::::new(3); + /// let u = NumVector::::from(&[1.0, 2.0]); + /// let v = NumVector::::from(&[3.0]); + /// + /// w.join2(u.as_data(), v.as_data()); + /// + /// assert_eq!(w.as_data(), &[1.0, 2.0, 3.0]); + /// ``` + pub fn join2(&mut self, u: &[T], v: &[T]) { + assert_eq!(u.len() + v.len(), self.data.len()); + (&mut self.data[..u.len()]).copy_from_slice(u); + (&mut self.data[u.len()..]).copy_from_slice(v); + } + /// Scales this vector /// /// ```text @@ -631,6 +688,10 @@ where /// Allows to access NumVector components using indices /// +/// # Panics +/// +/// The index function may panic if the index is out-of-bounds. +/// /// # Examples /// /// ``` @@ -640,10 +701,6 @@ where /// assert_eq!(u[1], 1.2); /// assert_eq!(u[2], 2.0); /// ``` -/// -/// # Panics -/// -/// The index function may panic if the index is out-of-bounds. impl Index for NumVector where T: MulAssign + Num + NumCast + Copy + DeserializeOwned + Serialize, @@ -657,6 +714,10 @@ where /// Allows to change NumVector components using indices /// +/// # Panics +/// +/// The index function may panic if the index is out-of-bounds. +/// /// # Examples /// /// ``` @@ -669,10 +730,6 @@ where /// assert_eq!(u[1], 11.2); /// assert_eq!(u[2], 22.0); /// ``` -/// -/// # Panics -/// -/// The index function may panic if the index is out-of-bounds. impl IndexMut for NumVector where T: MulAssign + Num + NumCast + Copy + DeserializeOwned + Serialize, @@ -948,6 +1005,43 @@ mod tests { assert_eq!(u.data, &[8.0, 9.0]); } + #[test] + #[should_panic] + fn split2_panics_on_wrong_lengths() { + let w = NumVector::::from(&[1.0, 2.0, 3.0]); + let mut u = NumVector::::new(2); + let mut v = NumVector::::new(2); // WRONG length + w.split2(u.as_mut_data(), v.as_mut_data()); + } + + #[test] + fn split2_works() { + let w = NumVector::::from(&[4.0, 5.0, -6.0]); + let mut u = NumVector::::new(2); + let mut v = NumVector::::new(1); + w.split2(u.as_mut_data(), v.as_mut_data()); + assert_eq!(u.as_data(), &[4.0, 5.0]); + assert_eq!(v.as_data(), &[-6.0]); + } + + #[test] + #[should_panic] + fn join2_panics_on_wrong_lengths() { + let mut w = NumVector::::new(2); // WRONG length + let u = NumVector::::from(&[1.0, 2.0]); + let v = NumVector::::from(&[3.0]); + w.join2(u.as_data(), v.as_data()); + } + + #[test] + fn join2_works() { + let mut w = NumVector::::new(4); + let u = NumVector::::from(&[9.0, -1.0, 7.0]); + let v = NumVector::::from(&[8.0]); + w.join2(u.as_data(), v.as_data()); + assert_eq!(w.as_data(), &[9.0, -1.0, 7.0, 8.0]); + } + #[test] fn scale_works() { let mut u = NumVector::::from(&[2.0, 4.0]); From 3f79eca17c96d2daeb3cd2d24f33a100bd3b3f28 Mon Sep 17 00:00:00 2001 From: Dorival Pedroso Date: Thu, 30 May 2024 10:45:57 +1000 Subject: [PATCH 6/7] [ode] Fix doc comment --- russell_ode/src/ode_solver.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/russell_ode/src/ode_solver.rs b/russell_ode/src/ode_solver.rs index 20221b3e..8097a829 100644 --- a/russell_ode/src/ode_solver.rs +++ b/russell_ode/src/ode_solver.rs @@ -134,7 +134,7 @@ impl<'a, A> OdeSolver<'a, A> { /// # Generics /// /// * `A` -- generic argument to assist in the f(x,y) and Jacobian functions. - /// It may be simply [NoArgs] indicating that no arguments are needed. + /// It may be simply [crate::NoArgs] indicating that no arguments are needed. pub fn new(params: Params, system: System<'a, A>) -> Result where A: 'a, From 0154f3de6d8a5eedba437d49df011f3f1957d059 Mon Sep 17 00:00:00 2001 From: Dorival Pedroso Date: Mon, 3 Jun 2024 12:58:44 +1000 Subject: [PATCH 7/7] [ode] Fix bug: at least two output stations are required for dense output --- russell_ode/src/output.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/russell_ode/src/output.rs b/russell_ode/src/output.rs index 5888f042..116f0c35 100644 --- a/russell_ode/src/output.rs +++ b/russell_ode/src/output.rs @@ -389,7 +389,7 @@ impl<'a, A> Output<'a, A> { if self.with_dense_output() { if let Some(h_out) = self.dense_h_out { // uniform spacing - let n = ((x1 - x0) / h_out) as usize + 1; + let n = usize::max(2, ((x1 - x0) / h_out) as usize + 1); // at least 2 (first and last) are required if self.dense_x.len() != n { self.dense_x.resize(n, 0.0); } @@ -808,6 +808,14 @@ mod tests { assert_eq!(y0_out.len(), 4); } + #[test] + fn initialize_with_dense_output_works_at_least_two_stations() { + let mut out = Output::<'_, NoArgs>::new(); + out.set_dense_h_out(0.5).unwrap().set_dense_recording(&[0]); + out.initialize(0.99, 1.0, false).unwrap(); + assert_eq!(out.dense_x.len(), 2); + } + #[test] fn initialize_with_step_output_works() { let mut out = Output::<'_, NoArgs>::new();