diff --git a/.github/workflows/build-tests.yml b/.github/workflows/build-tests.yml index 0cc4685..1234b95 100644 --- a/.github/workflows/build-tests.yml +++ b/.github/workflows/build-tests.yml @@ -17,6 +17,8 @@ jobs: steps: - uses: actions/checkout@v4 + - name: format + run: cargo fmt --check - name: Build run: cargo build --verbose - name: Run tests default diff --git a/src/approximation/linear_approximation.rs b/src/approximation/linear_approximation.rs index c42e7e3..44aceb0 100644 --- a/src/approximation/linear_approximation.rs +++ b/src/approximation/linear_approximation.rs @@ -3,105 +3,101 @@ use crate::numerical_derivative::derivator::DerivatorMultiVariable; use num_complex::ComplexFloat; #[derive(Debug)] -pub struct LinearApproximationResult -{ +pub struct LinearApproximationResult { pub intercept: T, - pub coefficients: [T; NUM_VARS] + pub coefficients: [T; NUM_VARS], } #[derive(Debug)] -pub struct LinearApproximationPredictionMetrics -{ +pub struct LinearApproximationPredictionMetrics { pub mean_absolute_error: T::Real, pub mean_squared_error: T::Real, pub root_mean_squared_error: T::Real, pub r_squared: T::Real, - pub adjusted_r_squared: T::Real + pub adjusted_r_squared: T::Real, } -impl LinearApproximationResult -{ +impl LinearApproximationResult { ///Helper function if you don't care about the details and just want the predictor directly - pub fn get_prediction_value(&self, args: &[T; NUM_VARS]) -> T - { + pub fn get_prediction_value(&self, args: &[T; NUM_VARS]) -> T { let mut result = self.intercept; - for (iter, arg) in args.iter().enumerate().take(NUM_VARS) - { - result = result + self.coefficients[iter]**arg; + for (iter, arg) in args.iter().enumerate().take(NUM_VARS) { + result = result + self.coefficients[iter] * *arg; } - + return result; } //get prediction metrics by feeding a list of points and the original function - pub fn get_prediction_metrics(&self, points: &[[T; NUM_VARS]; NUM_POINTS], original_function: &dyn Fn(&[T; NUM_VARS]) -> T) -> LinearApproximationPredictionMetrics - { + pub fn get_prediction_metrics( + &self, + points: &[[T; NUM_VARS]; NUM_POINTS], + original_function: &dyn Fn(&[T; NUM_VARS]) -> T, + ) -> LinearApproximationPredictionMetrics { //let num_points = NUM_POINTS as f64; let mut mae = T::zero(); let mut mse = T::zero(); - - for point in points.iter().take(NUM_POINTS) - { + + for point in points.iter().take(NUM_POINTS) { let predicted_y = self.get_prediction_value(point); - + mae = mae + (predicted_y - original_function(point)); mse = mse + num_complex::ComplexFloat::powi(predicted_y - original_function(point), 2); } - mae = mae/T::from(NUM_POINTS).unwrap(); - mse = mse/T::from(NUM_POINTS).unwrap(); + mae = mae / T::from(NUM_POINTS).unwrap(); + mse = mse / T::from(NUM_POINTS).unwrap(); let rmse = mse.sqrt().abs(); let mut r2_numerator = T::zero(); let mut r2_denominator = T::zero(); - for point in points.iter().take(NUM_POINTS) - { + for point in points.iter().take(NUM_POINTS) { let predicted_y = self.get_prediction_value(point); - r2_numerator = r2_numerator + num_complex::ComplexFloat::powi(predicted_y - original_function(point), 2); - r2_denominator = r2_numerator + num_complex::ComplexFloat::powi(mae - original_function(point), 2); + r2_numerator = r2_numerator + + num_complex::ComplexFloat::powi(predicted_y - original_function(point), 2); + r2_denominator = + r2_numerator + num_complex::ComplexFloat::powi(mae - original_function(point), 2); } - let r2 = T::one() - (r2_numerator/r2_denominator); + let r2 = T::one() - (r2_numerator / r2_denominator); - let r2_adj = T::one() - (T::one() - r2)*(T::from(NUM_POINTS).unwrap())/(T::from(NUM_POINTS).unwrap() - T::from(2.0).unwrap()); + let r2_adj = T::one() + - (T::one() - r2) * (T::from(NUM_POINTS).unwrap()) + / (T::from(NUM_POINTS).unwrap() - T::from(2.0).unwrap()); - return LinearApproximationPredictionMetrics - { + return LinearApproximationPredictionMetrics { mean_absolute_error: mae.abs(), mean_squared_error: mse.abs(), root_mean_squared_error: rmse, r_squared: r2.abs(), - adjusted_r_squared: r2_adj.abs() + adjusted_r_squared: r2_adj.abs(), }; } } -pub struct LinearApproximator -{ - derivator: D +pub struct LinearApproximator { + derivator: D, } -impl Default for LinearApproximator -{ - fn default() -> Self - { - return LinearApproximator { derivator: D::default() }; +impl Default for LinearApproximator { + fn default() -> Self { + return LinearApproximator { + derivator: D::default(), + }; } } -impl LinearApproximator -{ - pub fn from_derivator(derivator: D) -> Self - { - return LinearApproximator {derivator} +impl LinearApproximator { + pub fn from_derivator(derivator: D) -> Self { + return LinearApproximator { derivator }; } /// For an n-dimensional approximation, the equation is linearized as: /// coefficient[0]*var_1 + coefficient[1]*var_2 + ... + coefficient[n-1]*var_n + intercept - /// + /// /// NOTE: Returns a Result /// Possible &'static str are: /// NumberOfStepsCannotBeZero -> if the derivative step size is zero @@ -110,9 +106,9 @@ impl LinearApproximator ///``` ///use multicalc::approximation::linear_approximation::*; ///use multicalc::numerical_derivative::finite_difference::MultiVariableSolver; - /// + /// ///let function_to_approximate = | args: &[f64; 3] | -> f64 - ///{ + ///{ /// return args[0] + args[1].powf(2.0) + args[2].powf(3.0); ///}; /// @@ -123,29 +119,30 @@ impl LinearApproximator ///assert!(f64::abs(function_to_approximate(&point) - result.get_prediction_value(&point)) < 1e-9); /// ``` /// you can also inspect the results of the approximation. For an n-dimensional approximation, the equation is linearized as - /// + /// /// [`LinearApproximationResult::intercept`] gives you the required intercept /// [`LinearApproximationResult::coefficients`] gives you the required coefficients in order - /// + /// /// if you don't care about the results and want the predictor directly, use [`LinearApproximationResult::get_prediction_value()`] /// you can also inspect the prediction metrics by providing list of points, use [`LinearApproximationResult::get_prediction_metrics()`] /// - pub fn get(&self, function: &dyn Fn(&[T; NUM_VARS]) -> T, point: &[T; NUM_VARS]) -> Result, &'static str> - { + pub fn get( + &self, + function: &dyn Fn(&[T; NUM_VARS]) -> T, + point: &[T; NUM_VARS], + ) -> Result, &'static str> { let mut slopes_ = [T::zero(); NUM_VARS]; let mut intercept_ = function(point); - for iter in 0..NUM_VARS - { + for iter in 0..NUM_VARS { slopes_[iter] = self.derivator.get(1, function, &[iter], point)?; - intercept_ = intercept_ - slopes_[iter]*point[iter]; + intercept_ = intercept_ - slopes_[iter] * point[iter]; } - return Ok(LinearApproximationResult - { + return Ok(LinearApproximationResult { intercept: intercept_, - coefficients: slopes_ + coefficients: slopes_, }); } -} \ No newline at end of file +} diff --git a/src/approximation/mod.rs b/src/approximation/mod.rs index 70c4674..cd768a1 100644 --- a/src/approximation/mod.rs +++ b/src/approximation/mod.rs @@ -2,4 +2,4 @@ pub mod linear_approximation; pub mod quadratic_approximation; #[cfg(test)] -mod test; \ No newline at end of file +mod test; diff --git a/src/approximation/quadratic_approximation.rs b/src/approximation/quadratic_approximation.rs index 7910cc5..530c6c8 100644 --- a/src/approximation/quadratic_approximation.rs +++ b/src/approximation/quadratic_approximation.rs @@ -4,190 +4,184 @@ use crate::numerical_derivative::hessian::Hessian; use num_complex::ComplexFloat; #[derive(Debug)] -pub struct QuadraticApproximationResult -{ +pub struct QuadraticApproximationResult { pub intercept: T, pub linear_coefficients: [T; NUM_VARS], - pub quadratic_coefficients: [[T; NUM_VARS]; NUM_VARS] + pub quadratic_coefficients: [[T; NUM_VARS]; NUM_VARS], } #[derive(Debug)] -pub struct QuadraticApproximationPredictionMetrics -{ +pub struct QuadraticApproximationPredictionMetrics { pub mean_absolute_error: T::Real, pub mean_squared_error: T::Real, pub root_mean_squared_error: T::Real, pub r_squared: T::Real, - pub adjusted_r_squared: T::Real + pub adjusted_r_squared: T::Real, } ///Helper functions if you don't care about the details and just want the predictor directly -impl QuadraticApproximationResult -{ - pub fn get_prediction_value(&self, args: &[T; NUM_VARS]) -> T - { +impl QuadraticApproximationResult { + pub fn get_prediction_value(&self, args: &[T; NUM_VARS]) -> T { let mut result = self.intercept; - for (i, arg) in args.iter().enumerate().take(NUM_VARS) - { - result = result + self.linear_coefficients[i]**arg; + for (i, arg) in args.iter().enumerate().take(NUM_VARS) { + result = result + self.linear_coefficients[i] * *arg; } - for i in 0..NUM_VARS - { - for j in 1..NUM_VARS - { - result = result + self.quadratic_coefficients[i][j]*args[i]*args[j]; + for i in 0..NUM_VARS { + for j in 1..NUM_VARS { + result = result + self.quadratic_coefficients[i][j] * args[i] * args[j]; } } - + return result; } //get prediction metrics by feeding a list of points and the original function - pub fn get_prediction_metrics(&self, points: &[[T; NUM_VARS]; NUM_POINTS], original_function: &dyn Fn(&[T; NUM_VARS]) -> T) -> QuadraticApproximationPredictionMetrics - { + pub fn get_prediction_metrics( + &self, + points: &[[T; NUM_VARS]; NUM_POINTS], + original_function: &dyn Fn(&[T; NUM_VARS]) -> T, + ) -> QuadraticApproximationPredictionMetrics { //let num_points = points.len() as f64; let mut mae = T::zero(); let mut mse = T::zero(); - - for point in points.iter().take(NUM_POINTS) - { + + for point in points.iter().take(NUM_POINTS) { let predicted_y = self.get_prediction_value(point); - + mae = mae + (predicted_y - original_function(point)); mse = mse + num_complex::ComplexFloat::powi(predicted_y - original_function(point), 2); } - mae = mae/T::from(NUM_POINTS).unwrap(); - mse = mse/T::from(NUM_POINTS).unwrap(); + mae = mae / T::from(NUM_POINTS).unwrap(); + mse = mse / T::from(NUM_POINTS).unwrap(); let rmse = mse.sqrt().abs(); let mut r2_numerator = T::zero(); let mut r2_denominator = T::zero(); - for point in points.iter().take(NUM_POINTS) - { + for point in points.iter().take(NUM_POINTS) { let predicted_y = self.get_prediction_value(point); - r2_numerator = r2_numerator + num_complex::ComplexFloat::powi(predicted_y - original_function(point), 2); - r2_denominator = r2_numerator + num_complex::ComplexFloat::powi(mae - original_function(point), 2); + r2_numerator = r2_numerator + + num_complex::ComplexFloat::powi(predicted_y - original_function(point), 2); + r2_denominator = + r2_numerator + num_complex::ComplexFloat::powi(mae - original_function(point), 2); } - let r2 = T::one() - (r2_numerator/r2_denominator); + let r2 = T::one() - (r2_numerator / r2_denominator); - let r2_adj = T::one() - (T::one() - r2)*(T::from(NUM_POINTS).unwrap())/(T::from(NUM_POINTS).unwrap() - T::from(2.0).unwrap()); + let r2_adj = T::one() + - (T::one() - r2) * (T::from(NUM_POINTS).unwrap()) + / (T::from(NUM_POINTS).unwrap() - T::from(2.0).unwrap()); - return QuadraticApproximationPredictionMetrics - { + return QuadraticApproximationPredictionMetrics { mean_absolute_error: mae.abs(), mean_squared_error: mse.abs(), root_mean_squared_error: rmse, r_squared: r2.abs(), - adjusted_r_squared: r2_adj.abs() + adjusted_r_squared: r2_adj.abs(), }; } } -pub struct QuadraticApproximator -{ +pub struct QuadraticApproximator { derivator: D, } -impl Default for QuadraticApproximator -{ - fn default() -> Self - { - return QuadraticApproximator { derivator: D::default()}; +impl Default for QuadraticApproximator { + fn default() -> Self { + return QuadraticApproximator { + derivator: D::default(), + }; } } -impl QuadraticApproximator -{ - pub fn from_derivator(derivator: D) -> Self - { - return QuadraticApproximator {derivator}; +impl QuadraticApproximator { + pub fn from_derivator(derivator: D) -> Self { + return QuadraticApproximator { derivator }; } /// For an n-dimensional approximation, the equation is approximated as I + L + Q, where: - /// I = intercept + /// I = intercept /// L = linear_coefficients[0]*var_1 + linear_coefficients[1]*var_2 + ... + linear_coefficients[n-1]*var_n /// Q = quadratic_coefficients[0][0]*var_1*var_1 + quadratic_coefficients[0][1]*var_1*var_2 + ... + quadratic_coefficients[n-1][n-1]*var_n*var_n /// /// NOTE: Returns a Result /// Possible &'static str are: /// NumberOfStepsCannotBeZero -> if the derivative step size is zero - /// + /// ///example function is e^(x/2) + sin(y) + 2.0*z, which we want to approximate. First define the function: ///``` ///use multicalc::approximation::quadratic_approximation::*; ///use multicalc::numerical_derivative::finite_difference::MultiVariableSolver; - /// + /// ///let function_to_approximate = | args: &[f64; 3] | -> f64 - ///{ + ///{ /// return f64::exp(args[0]/2.0) + f64::sin(args[1]) + 2.0*args[2]; ///}; /// ///let point = [0.0, 1.57, 10.0]; //the point we want to approximate around - /// + /// ///let approximator = QuadraticApproximator::::default(); ///let result = approximator.get(&function_to_approximate, &point).unwrap(); /// ///assert!(f64::abs(function_to_approximate(&point) - result.get_prediction_value(&point)) < 1e-9); /// ``` /// you can also inspect the results of the approximation. For an n-dimensional approximation, the equation is linearized as - /// + /// /// [`QuadraticApproximationResult::intercept`] gives you the required intercept /// [`QuadraticApproximationResult::linear_coefficients`] gives you the required linear coefficients in order /// [`QuadraticApproximationResult::quadratic_coefficients`] gives you the required quadratic coefficients as a matrix - /// + /// /// if you don't care about the results and want the predictor directly, use [`QuadraticApproximationResult::get_prediction_value()`] /// you can also inspect the prediction metrics by providing list of points, use [`QuadraticApproximationResult::get_prediction_metrics()`] - /// + /// /// to see how the [QuadraticApproximationResult::quadratic_coefficients] matrix should be used, refer to [`QuadraticApproximationResult::get_prediction_metrics()`] /// or refer to its tests. /// - pub fn get(&self, function: &dyn Fn(&[T; NUM_VARS]) -> T, point: &[T; NUM_VARS]) -> Result, &'static str> - { + pub fn get( + &self, + function: &dyn Fn(&[T; NUM_VARS]) -> T, + point: &[T; NUM_VARS], + ) -> Result, &'static str> { let mut intercept_ = function(point); let mut linear_coeffs_ = [T::zero(); NUM_VARS]; let hessian_matrix = Hessian::from_derivator(self.derivator).get(function, point)?; - for iter in 0..NUM_VARS - { + for iter in 0..NUM_VARS { linear_coeffs_[iter] = self.derivator.get(1, function, &[iter], point)?; - intercept_ = intercept_ - self.derivator.get(1, function, &[iter], point)?*point[iter]; + intercept_ = + intercept_ - self.derivator.get(1, function, &[iter], point)? * point[iter]; } let mut quad_coeff = [[T::zero(); NUM_VARS]; NUM_VARS]; - for row in 0..NUM_VARS - { - for col in row..NUM_VARS - { + for row in 0..NUM_VARS { + for col in row..NUM_VARS { quad_coeff[row][col] = hessian_matrix[row][col]; - intercept_ = intercept_ + hessian_matrix[row][col]*point[row]*point[row]; + intercept_ = intercept_ + hessian_matrix[row][col] * point[row] * point[row]; - if row == col - { - linear_coeffs_[row] = linear_coeffs_[row] - T::from(2.0).unwrap()*hessian_matrix[row][col]*point[row] - } - else - { - linear_coeffs_[row] = linear_coeffs_[row] - hessian_matrix[row][col]*point[col]; - linear_coeffs_[col] = linear_coeffs_[col] - hessian_matrix[row][col]*point[row]; + if row == col { + linear_coeffs_[row] = linear_coeffs_[row] + - T::from(2.0).unwrap() * hessian_matrix[row][col] * point[row] + } else { + linear_coeffs_[row] = + linear_coeffs_[row] - hessian_matrix[row][col] * point[col]; + linear_coeffs_[col] = + linear_coeffs_[col] - hessian_matrix[row][col] * point[row]; } } } - return Ok(QuadraticApproximationResult - { + return Ok(QuadraticApproximationResult { intercept: intercept_, linear_coefficients: linear_coeffs_, - quadratic_coefficients: quad_coeff + quadratic_coefficients: quad_coeff, }); } -} \ No newline at end of file +} diff --git a/src/approximation/test.rs b/src/approximation/test.rs index 8c94b42..b715b95 100644 --- a/src/approximation/test.rs +++ b/src/approximation/test.rs @@ -4,11 +4,9 @@ use crate::numerical_derivative::finite_difference::MultiVariableSolver; use rand::Rng; #[test] -fn test_linear_approximation_1() -{ +fn test_linear_approximation_1() { //function is x + y^2 + z^3, which we want to linearize - let function_to_approximate = | args: &[f64; 3] | -> f64 - { + let function_to_approximate = |args: &[f64; 3]| -> f64 { return args[0] + args[1].powf(2.0) + args[2].powf(3.0); }; @@ -20,36 +18,33 @@ fn test_linear_approximation_1() assert!(f64::abs(function_to_approximate(&point) - result.get_prediction_value(&point)) < 1e-9); //now test the prediction metrics. For prediction, generate a list of 1000 points, all centered around the original point - //with random noise between [-0.1, +0.1) + //with random noise between [-0.1, +0.1) let mut prediction_points = [[0.0; 3]; 1000]; let mut random_generator = rand::thread_rng(); - for iter in 0..1000 - { + for iter in 0..1000 { let noise = random_generator.gen_range(-0.1..0.1); prediction_points[iter] = [point[0] + noise, point[1] + noise, point[2] + noise]; } - - let prediction_metrics = result.get_prediction_metrics(&prediction_points, &function_to_approximate); + + let prediction_metrics = + result.get_prediction_metrics(&prediction_points, &function_to_approximate); assert!(prediction_metrics.root_mean_squared_error < 0.05); assert!(prediction_metrics.mean_absolute_error < 0.05); assert!(prediction_metrics.mean_squared_error < 0.05); assert!(prediction_metrics.r_squared > 0.99); assert!(prediction_metrics.adjusted_r_squared > 0.99); - } #[test] -fn test_quadratic_approximation_1() -{ +fn test_quadratic_approximation_1() { //function is e^(x/2) + sin(y) + 2.0*z - let function_to_approximate = | args: &[f64; 3] | -> f64 - { - return f64::exp(args[0]/2.0) + f64::sin(args[1]) + 2.0*args[2]; + let function_to_approximate = |args: &[f64; 3]| -> f64 { + return f64::exp(args[0] / 2.0) + f64::sin(args[1]) + 2.0 * args[2]; }; - let point = [0.0, 3.14/2.0, 10.0]; //the point we want to approximate around + let point = [0.0, 3.14 / 2.0, 10.0]; //the point we want to approximate around let approximator = QuadraticApproximator::::default(); @@ -58,21 +53,21 @@ fn test_quadratic_approximation_1() assert!(f64::abs(function_to_approximate(&point) - result.get_prediction_value(&point)) < 1e-9); //now test the prediction metrics. For prediction, generate a list of 1000 points, all centered around the original point - //with random noise between [-0.1, +0.1) + //with random noise between [-0.1, +0.1) let mut prediction_points = [[0.0; 3]; 1000]; let mut random_generator = rand::thread_rng(); - for iter in 0..1000 - { + for iter in 0..1000 { let noise = random_generator.gen_range(-0.1..0.1); - prediction_points[iter] = [0.0 + noise, (3.14/2.0) + noise, 10.0 + noise]; + prediction_points[iter] = [0.0 + noise, (3.14 / 2.0) + noise, 10.0 + noise]; } - let prediction_metrics = result.get_prediction_metrics(&prediction_points, &function_to_approximate); + let prediction_metrics = + result.get_prediction_metrics(&prediction_points, &function_to_approximate); assert!(prediction_metrics.root_mean_squared_error < 0.01); assert!(prediction_metrics.mean_absolute_error < 0.01); assert!(prediction_metrics.mean_squared_error < 1e-5); assert!(prediction_metrics.r_squared > 0.9999); assert!(prediction_metrics.adjusted_r_squared > 0.9999); -} \ No newline at end of file +} diff --git a/src/lib.rs b/src/lib.rs index e58d3b5..a5ff137 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,13 +1,12 @@ #![allow(clippy::needless_return)] #![allow(clippy::type_complexity)] - #![no_std] #[cfg(feature = "heap")] extern crate std; -pub mod utils; -pub mod numerical_integration; -pub mod numerical_derivative; pub mod approximation; -pub mod vector_field; \ No newline at end of file +pub mod numerical_derivative; +pub mod numerical_integration; +pub mod utils; +pub mod vector_field; diff --git a/src/numerical_derivative/derivator.rs b/src/numerical_derivative/derivator.rs index 09787eb..3d2793b 100644 --- a/src/numerical_derivative/derivator.rs +++ b/src/numerical_derivative/derivator.rs @@ -1,41 +1,62 @@ use num_complex::ComplexFloat; - ///Base trait for single variable numerical differentiation -pub trait DerivatorSingleVariable: Default + Clone + Copy -{ +pub trait DerivatorSingleVariable: Default + Clone + Copy { ///generic n-th derivative of a single variable function - fn get(&self, order: usize, func: &dyn Fn(T) -> T, point: T) -> Result; + fn get( + &self, + order: usize, + func: &dyn Fn(T) -> T, + point: T, + ) -> Result; ///convenience wrapper for a single derivative of a single variable function - fn get_single(&self, func: &dyn Fn(T) -> T, point: T) -> Result - { + fn get_single( + &self, + func: &dyn Fn(T) -> T, + point: T, + ) -> Result { return self.get(1, func, point); } ///convenience wrapper for a double derivative of a single variable function - fn get_double(&self, func: &dyn Fn(T) -> T, point: T) -> Result - { + fn get_double( + &self, + func: &dyn Fn(T) -> T, + point: T, + ) -> Result { return self.get(2, func, point); } } - ///Base trait for multi-variable numerical differentiation -pub trait DerivatorMultiVariable: Default + Clone + Copy -{ +pub trait DerivatorMultiVariable: Default + Clone + Copy { ///generic n-th derivative for a multivariable function of a multivariable function - fn get(&self, order: usize, func: &dyn Fn(&[T; NUM_VARS]) -> T, idx_to_derivate: &[usize; NUM_ORDER], point: &[T; NUM_VARS]) -> Result; + fn get( + &self, + order: usize, + func: &dyn Fn(&[T; NUM_VARS]) -> T, + idx_to_derivate: &[usize; NUM_ORDER], + point: &[T; NUM_VARS], + ) -> Result; ///convenience wrapper for a single partial derivative of a multivariable function - fn get_single_partial(&self, func: &dyn Fn(&[T; NUM_VARS]) -> T, idx_to_derivate: usize, point: &[T; NUM_VARS]) -> Result - { + fn get_single_partial( + &self, + func: &dyn Fn(&[T; NUM_VARS]) -> T, + idx_to_derivate: usize, + point: &[T; NUM_VARS], + ) -> Result { return self.get(1, func, &[idx_to_derivate], point); } - + ///convenience wrapper for a double partial derivative of a multivariable function - fn get_double_partial(&self, func: &dyn Fn(&[T; NUM_VARS]) -> T, idx_to_derivate: &[usize; 2], point: &[T; NUM_VARS]) -> Result - { + fn get_double_partial( + &self, + func: &dyn Fn(&[T; NUM_VARS]) -> T, + idx_to_derivate: &[usize; 2], + point: &[T; NUM_VARS], + ) -> Result { return self.get(2, func, idx_to_derivate, point); } -} \ No newline at end of file +} diff --git a/src/numerical_derivative/finite_difference.rs b/src/numerical_derivative/finite_difference.rs index f764089..b551413 100644 --- a/src/numerical_derivative/finite_difference.rs +++ b/src/numerical_derivative/finite_difference.rs @@ -1,73 +1,62 @@ -use crate::numerical_derivative::mode; +use crate::numerical_derivative::mode; use crate::utils::error_codes::*; -use num_complex::ComplexFloat; use crate::numerical_derivative::derivator::*; +use num_complex::ComplexFloat; ///Implements the finite difference method for numerical differentation for single variable functions #[derive(Clone, Copy)] -pub struct SingleVariableSolver -{ +pub struct SingleVariableSolver { step_size: f64, method: mode::FiniteDifferenceMode, //the step size will be multipled by this factor after every iteration. Only matters for triple derivatives or higher - step_size_multiplier: f64 + step_size_multiplier: f64, } -impl Default for SingleVariableSolver -{ +impl Default for SingleVariableSolver { ///default constructor, choose this for optimal results for most generic equations - fn default() -> Self - { - return SingleVariableSolver - { + fn default() -> Self { + return SingleVariableSolver { step_size: mode::DEFAULT_STEP_SIZE, method: mode::FiniteDifferenceMode::Central, - step_size_multiplier: mode::DEFAULT_STEP_SIZE_MULTIPLIER + step_size_multiplier: mode::DEFAULT_STEP_SIZE_MULTIPLIER, }; } } -impl SingleVariableSolver -{ +impl SingleVariableSolver { ///Returns the step size - pub fn get_step_size(&self) -> f64 - { + pub fn get_step_size(&self) -> f64 { return self.step_size; } ///Sets the step size - pub fn set_step_size(&mut self, step_size: f64) - { + pub fn set_step_size(&mut self, step_size: f64) { self.step_size = step_size; } ///Returns the chosen method of differentiation ///Possible choices are: Forward step, backward step and central step - pub fn get_method(&self) -> mode::FiniteDifferenceMode - { + pub fn get_method(&self) -> mode::FiniteDifferenceMode { return self.method; } ///Sets the method of differentiation ///Possible choices are: Forward step, backward step and central step - pub fn set_method(&mut self, method: mode::FiniteDifferenceMode) - { + pub fn set_method(&mut self, method: mode::FiniteDifferenceMode) { self.method = method; } ///Returns the chosen step size multiplier - pub fn get_step_size_multiplier(&self) -> f64 - { + pub fn get_step_size_multiplier(&self) -> f64 { return self.step_size_multiplier; } ///Sets the chosen step size multiplier. The step size will /// be multiplied by this factor after every iteration /// This parameter only matters if you are interested in triple derivatives or higher - pub fn set_step_size_multiplier(&mut self, multiplier: f64) - { + pub fn set_step_size_multiplier(&mut self, multiplier: f64) { self.step_size_multiplier = multiplier; } @@ -76,105 +65,143 @@ impl SingleVariableSolver /// method: the desired method of differentiation: forward step, backward step or central step /// multiplier: default is 10.0, this is the factor by which we multiply the step size with on each iteration. /// Only matters for triple derivatives or higher - pub fn from_parameters(step: f64, method: mode::FiniteDifferenceMode, multiplier: f64) -> Self - { - SingleVariableSolver - { + pub fn from_parameters(step: f64, method: mode::FiniteDifferenceMode, multiplier: f64) -> Self { + SingleVariableSolver { step_size: step, method: method, - step_size_multiplier: multiplier - } + step_size_multiplier: multiplier, + } } ///Returns the forward difference numerical differentiation for single variable functions ///computes f'(x) = (f(x + h) - f(x))/h, where h is the chosen step size /// you can control how many times to differentiate using the "order" parameter - fn get_forward_difference_single_variable(&self, order: usize, func: &dyn Fn(T) -> T, point: T, step_size: f64) -> T - { - if order == 1 - { + fn get_forward_difference_single_variable( + &self, + order: usize, + func: &dyn Fn(T) -> T, + point: T, + step_size: f64, + ) -> T { + if order == 1 { let f0 = func(point); let f1 = func(point + T::from(step_size).unwrap()); - return (f1 - f0)/(T::from(step_size).unwrap()); + return (f1 - f0) / (T::from(step_size).unwrap()); } let f0_point = point; - let f0 = self.get_forward_difference_single_variable(order - 1, func, f0_point, self.step_size_multiplier*step_size); + let f0 = self.get_forward_difference_single_variable( + order - 1, + func, + f0_point, + self.step_size_multiplier * step_size, + ); let f1_point = point + T::from(step_size).unwrap(); - let f1 = self.get_forward_difference_single_variable(order - 1, func, f1_point, self.step_size_multiplier*step_size); - - return (f1 - f0)/(T::from(step_size).unwrap()); + let f1 = self.get_forward_difference_single_variable( + order - 1, + func, + f1_point, + self.step_size_multiplier * step_size, + ); + + return (f1 - f0) / (T::from(step_size).unwrap()); } ///Returns the backward difference numerical differentiation for single variable functions ///computes f'(x) = (f(x) - f(x - h))/h, where h is the chosen step size /// you can control how many times to differentiate using the "order" parameter - fn get_backward_difference_single_variable(&self, order: usize, func: &dyn Fn(T) -> T, point: T, step_size: f64) -> T - { - if order == 1 - { + fn get_backward_difference_single_variable( + &self, + order: usize, + func: &dyn Fn(T) -> T, + point: T, + step_size: f64, + ) -> T { + if order == 1 { let f0 = func(point - T::from(step_size).unwrap()); let f1 = func(point); - return (f1 - f0)/(T::from(step_size).unwrap()); + return (f1 - f0) / (T::from(step_size).unwrap()); } let f0_point = point - T::from(step_size).unwrap(); - let f0 = self.get_backward_difference_single_variable(order - 1, func, f0_point, self.step_size_multiplier*step_size); + let f0 = self.get_backward_difference_single_variable( + order - 1, + func, + f0_point, + self.step_size_multiplier * step_size, + ); let f1_point = point; - let f1 = self.get_backward_difference_single_variable(order - 1, func, f1_point, self.step_size_multiplier*step_size); - - return (f1 - f0)/(T::from(step_size).unwrap()); + let f1 = self.get_backward_difference_single_variable( + order - 1, + func, + f1_point, + self.step_size_multiplier * step_size, + ); + + return (f1 - f0) / (T::from(step_size).unwrap()); } - ///Returns the central difference numerical differentiation for single variable functions ///computes f'(x) = (f(x + h) - f(x - h))/2h, where h is the chosen step size /// you can control how many times to differentiate using the "order" parameter - fn get_central_difference_single_variable(&self, order: usize, func: &dyn Fn(T) -> T, point: T, step_size: f64) -> T - { - if order == 1 - { + fn get_central_difference_single_variable( + &self, + order: usize, + func: &dyn Fn(T) -> T, + point: T, + step_size: f64, + ) -> T { + if order == 1 { let f0 = func(point - T::from(step_size).unwrap()); let f1 = func(point + T::from(step_size).unwrap()); - return (f1 - f0)/(T::from(2.0*step_size).unwrap()); + return (f1 - f0) / (T::from(2.0 * step_size).unwrap()); } let f0_point = point - T::from(step_size).unwrap(); - let f0 = self.get_central_difference_single_variable(order - 1, func, f0_point, self.step_size_multiplier*step_size); + let f0 = self.get_central_difference_single_variable( + order - 1, + func, + f0_point, + self.step_size_multiplier * step_size, + ); let f1_point = point + T::from(step_size).unwrap(); - let f1 = self.get_central_difference_single_variable(order - 1, func, f1_point, self.step_size_multiplier*step_size); - - return (f1 - f0)/(T::from(2.0*step_size).unwrap()); + let f1 = self.get_central_difference_single_variable( + order - 1, + func, + f1_point, + self.step_size_multiplier * step_size, + ); + + return (f1 - f0) / (T::from(2.0 * step_size).unwrap()); } } -impl DerivatorSingleVariable for SingleVariableSolver -{ +impl DerivatorSingleVariable for SingleVariableSolver { /// Returns the numerical differentiation value for a single variable function /// order: number of times the equation should be differentiated /// func: the single variable function /// point: the point of interest around which we want to differentiate - /// + /// /// NOTE: Returns a Result /// Possible &'static str are: /// NUMBER_OF_DERIVATIVE_STEPS_CANNOT_BE_ZERO -> if the step size value is zero /// DERIVATE_ORDER_CANNOT_BE_ZERO -> if the 'order' argument is zero - /// + /// /// assume we want to differentiate f(x) = x^3. the function would be: /// ``` - /// let my_func = | arg: f64 | -> f64 - /// { + /// let my_func = | arg: f64 | -> f64 + /// { /// return arg*arg*arg; /// }; /// /// let point = 2.0; //the point at which we want to differentiate - /// + /// /// use multicalc::numerical_derivative::derivator::*; /// use multicalc::numerical_derivative::finite_difference::*; - /// + /// /// let derivator = SingleVariableSolver::default(); /// let val = derivator.get(1, &my_func, point).unwrap(); //single derivative /// assert!(f64::abs(val - 12.0) < 1e-7); @@ -182,95 +209,106 @@ impl DerivatorSingleVariable for SingleVariableSolver /// assert!(f64::abs(val - 12.0) < 1e-5); /// let val = derivator.get(3, &my_func, point).unwrap(); //triple derivative /// assert!(f64::abs(val - 6.0) < 1e-3); - /// + /// ///``` - ///// Note that the accuracy of approximations fall with every derivative. This can be fine-tuned for each case + ///// Note that the accuracy of approximations fall with every derivative. This can be fine-tuned for each case /// using an appropriate starting step size and a step size multiplier - fn get(&self, order: usize, func: &dyn Fn(T) -> T, point: T) -> Result - { - if order == 0 - { + fn get( + &self, + order: usize, + func: &dyn Fn(T) -> T, + point: T, + ) -> Result { + if order == 0 { return Err(DERIVATE_ORDER_CANNOT_BE_ZERO); } - if self.step_size == 0.0 - { + if self.step_size == 0.0 { return Err(NUMBER_OF_DERIVATIVE_STEPS_CANNOT_BE_ZERO); } - match self.method - { - mode::FiniteDifferenceMode::Forward => return Ok(self.get_forward_difference_single_variable(order, func, point, self.step_size)), - mode::FiniteDifferenceMode::Backward => return Ok(self.get_backward_difference_single_variable(order, func, point, self.step_size)), - mode::FiniteDifferenceMode::Central => return Ok(self.get_central_difference_single_variable(order, func, point, self.step_size)) - } + match self.method { + mode::FiniteDifferenceMode::Forward => { + return Ok(self.get_forward_difference_single_variable( + order, + func, + point, + self.step_size, + )) + } + mode::FiniteDifferenceMode::Backward => { + return Ok(self.get_backward_difference_single_variable( + order, + func, + point, + self.step_size, + )) + } + mode::FiniteDifferenceMode::Central => { + return Ok(self.get_central_difference_single_variable( + order, + func, + point, + self.step_size, + )) + } + } } } ///Implements the finite difference method for numerical differentation for multi-variable functions #[derive(Clone, Copy)] -pub struct MultiVariableSolver -{ +pub struct MultiVariableSolver { step_size: f64, method: mode::FiniteDifferenceMode, //the step size will be multiplied by this factor after every iteration. Only matters for triple derivatives or higher - step_size_multiplier: f64 + step_size_multiplier: f64, } -impl Default for MultiVariableSolver -{ +impl Default for MultiVariableSolver { ///default constructor, choose this for optimal results for most generic equations - fn default() -> Self - { - return MultiVariableSolver - { + fn default() -> Self { + return MultiVariableSolver { step_size: mode::DEFAULT_STEP_SIZE, method: mode::FiniteDifferenceMode::Central, - step_size_multiplier: mode::DEFAULT_STEP_SIZE_MULTIPLIER + step_size_multiplier: mode::DEFAULT_STEP_SIZE_MULTIPLIER, }; } } -impl MultiVariableSolver -{ +impl MultiVariableSolver { ///Returns the step size - pub fn get_step_size(&self) -> f64 - { + pub fn get_step_size(&self) -> f64 { return self.step_size; } ///Sets the step size - pub fn set_step_size(&mut self, step_size: f64) - { + pub fn set_step_size(&mut self, step_size: f64) { self.step_size = step_size; } ///Returns the chosen method of differentiation ///Possible choices are: Forward step, backward step and central step - pub fn get_method(&self) -> mode::FiniteDifferenceMode - { + pub fn get_method(&self) -> mode::FiniteDifferenceMode { return self.method; } ///Sets the method of differentiation ///Possible choices are: Forward step, backward step and central step - pub fn set_method(&mut self, method: mode::FiniteDifferenceMode) - { + pub fn set_method(&mut self, method: mode::FiniteDifferenceMode) { self.method = method; } ///Returns the chosen step size multiplier. - pub fn get_step_size_multiplier(&self) -> f64 - { + pub fn get_step_size_multiplier(&self) -> f64 { return self.step_size_multiplier; } ///Sets the chosen step size multiplier. The step size will /// be multiplied by this factor after every iteration /// This parameter only matters if you are interested in triple derivatives or higher - pub fn set_step_size_multiplier(&mut self, multiplier: f64) - { + pub fn set_step_size_multiplier(&mut self, multiplier: f64) { self.step_size_multiplier = multiplier; } @@ -279,177 +317,264 @@ impl MultiVariableSolver /// method: the desired method of differentiation: forward step, backward step or central step /// multiplier: default is 10.0, this is the factor by which we multiply the step size with on each iteration. /// Only matters for triple derivatives or higher - pub fn from_parameters(step: f64, method: mode::FiniteDifferenceMode, multiplier: f64) -> Self - { - MultiVariableSolver - { + pub fn from_parameters(step: f64, method: mode::FiniteDifferenceMode, multiplier: f64) -> Self { + MultiVariableSolver { step_size: step, method: method, - step_size_multiplier: multiplier - } + step_size_multiplier: multiplier, + } } ///Returns the partial forward difference numerical differentiation for multi variable functions ///computes f'(X) = (f(X + h) - f(X))/h, where h is the chosen step size /// you can control how many times to differentiate using the "order" parameter /// you can specify the variable(s) whose respect to the equation needs to be differentiated using the 'idx_to_derivate' parameter - fn get_forward_difference_multi_variable(&self, order: usize, func: &dyn Fn(&[T; NUM_VARS]) -> T, idx_to_derivate: &[usize; NUM_ORDER], point: &[T; NUM_VARS], step_size: f64) -> T - { - if order == 1 - { + fn get_forward_difference_multi_variable< + T: ComplexFloat, + const NUM_VARS: usize, + const NUM_ORDER: usize, + >( + &self, + order: usize, + func: &dyn Fn(&[T; NUM_VARS]) -> T, + idx_to_derivate: &[usize; NUM_ORDER], + point: &[T; NUM_VARS], + step_size: f64, + ) -> T { + if order == 1 { let f0_args = point; let mut f1_args = *point; - f1_args[idx_to_derivate[0]] = f1_args[idx_to_derivate[0]] + T::from(step_size).unwrap(); + f1_args[idx_to_derivate[0]] = f1_args[idx_to_derivate[0]] + T::from(step_size).unwrap(); let f0 = func(f0_args); let f1 = func(&f1_args); - return (f1 - f0)/T::from(step_size).unwrap(); + return (f1 - f0) / T::from(step_size).unwrap(); } let f0_args = point; let mut f1_args = *point; - f1_args[idx_to_derivate[order - 1]] = f1_args[idx_to_derivate[order - 1]] + T::from(step_size).unwrap(); - - let f0 = self.get_forward_difference_multi_variable(order - 1, func, idx_to_derivate, f0_args, self.step_size_multiplier*step_size); - let f1 = self.get_forward_difference_multi_variable(order - 1, func, idx_to_derivate, &f1_args, self.step_size_multiplier*step_size); - - return (f1 - f0)/T::from(step_size).unwrap(); + f1_args[idx_to_derivate[order - 1]] = + f1_args[idx_to_derivate[order - 1]] + T::from(step_size).unwrap(); + + let f0 = self.get_forward_difference_multi_variable( + order - 1, + func, + idx_to_derivate, + f0_args, + self.step_size_multiplier * step_size, + ); + let f1 = self.get_forward_difference_multi_variable( + order - 1, + func, + idx_to_derivate, + &f1_args, + self.step_size_multiplier * step_size, + ); + + return (f1 - f0) / T::from(step_size).unwrap(); } ///Returns the partial backward difference numerical differentiation for multi variable functions ///computes f'(X) = (f(X) - f(X - h))/h, where h is the chosen step size /// you can control how many times to differentiate using the "order" parameter /// you can specify the variable(s) whose respect to the equation needs to be differentiated using the 'idx_to_derivate' parameter - fn get_backward_difference_multi_variable(&self, order: usize, func: &dyn Fn(&[T; NUM_VARS]) -> T, idx_to_derivate: &[usize; NUM_ORDER], point: &[T; NUM_VARS], step_size: f64) -> T - { - if order == 1 - { + fn get_backward_difference_multi_variable< + T: ComplexFloat, + const NUM_VARS: usize, + const NUM_ORDER: usize, + >( + &self, + order: usize, + func: &dyn Fn(&[T; NUM_VARS]) -> T, + idx_to_derivate: &[usize; NUM_ORDER], + point: &[T; NUM_VARS], + step_size: f64, + ) -> T { + if order == 1 { let mut f0_args = *point; - f0_args[idx_to_derivate[0]] = f0_args[idx_to_derivate[0]] - T::from(step_size).unwrap(); + f0_args[idx_to_derivate[0]] = f0_args[idx_to_derivate[0]] - T::from(step_size).unwrap(); let f1_args = point; let f0 = func(&f0_args); let f1 = func(f1_args); - return (f1 - f0)/T::from(step_size).unwrap(); + return (f1 - f0) / T::from(step_size).unwrap(); } let mut f0_args = *point; - f0_args[idx_to_derivate[order - 1]] = f0_args[idx_to_derivate[order - 1]] - T::from(step_size).unwrap(); + f0_args[idx_to_derivate[order - 1]] = + f0_args[idx_to_derivate[order - 1]] - T::from(step_size).unwrap(); let f1_args = point; - let f0 = self.get_backward_difference_multi_variable(order - 1, func, idx_to_derivate, &f0_args, self.step_size_multiplier*step_size); - let f1 = self.get_backward_difference_multi_variable(order - 1, func, idx_to_derivate, f1_args, self.step_size_multiplier*step_size); - - return (f1 - f0)/T::from(step_size).unwrap(); + let f0 = self.get_backward_difference_multi_variable( + order - 1, + func, + idx_to_derivate, + &f0_args, + self.step_size_multiplier * step_size, + ); + let f1 = self.get_backward_difference_multi_variable( + order - 1, + func, + idx_to_derivate, + f1_args, + self.step_size_multiplier * step_size, + ); + + return (f1 - f0) / T::from(step_size).unwrap(); } ///Returns the partial central difference numerical differentiation for multi variable functions ///computes f'(X) = (f(X + h) - f(X - h))/2h, where h is the chosen step size /// you can control how many times to differentiate using the "order" parameter /// you can specify the variable(s) whose respect to the equation needs to be differentiated using the 'idx_to_derivate' parameter - fn get_central_difference_multi_variable(&self, order: usize, func: &dyn Fn(&[T; NUM_VARS]) -> T, idx_to_derivate: &[usize; NUM_ORDER], point: &[T; NUM_VARS], step_size: f64) -> T - { - if order == 1 - { + fn get_central_difference_multi_variable< + T: ComplexFloat, + const NUM_VARS: usize, + const NUM_ORDER: usize, + >( + &self, + order: usize, + func: &dyn Fn(&[T; NUM_VARS]) -> T, + idx_to_derivate: &[usize; NUM_ORDER], + point: &[T; NUM_VARS], + step_size: f64, + ) -> T { + if order == 1 { let mut f0_args = *point; f0_args[idx_to_derivate[0]] = f0_args[idx_to_derivate[0]] - T::from(step_size).unwrap(); let mut f1_args = *point; - f1_args[idx_to_derivate[0]] = f1_args[idx_to_derivate[0]] + T::from(step_size).unwrap(); + f1_args[idx_to_derivate[0]] = f1_args[idx_to_derivate[0]] + T::from(step_size).unwrap(); let f0 = func(&f0_args); let f1 = func(&f1_args); - return (f1 - f0)/(T::from(2.0*step_size).unwrap()); + return (f1 - f0) / (T::from(2.0 * step_size).unwrap()); } let mut f0_point = *point; - f0_point[idx_to_derivate[order - 1]] = f0_point[idx_to_derivate[order - 1]] - T::from(step_size).unwrap(); + f0_point[idx_to_derivate[order - 1]] = + f0_point[idx_to_derivate[order - 1]] - T::from(step_size).unwrap(); - let f0 = self.get_central_difference_multi_variable(order - 1, func, idx_to_derivate, &f0_point, self.step_size_multiplier*step_size); + let f0 = self.get_central_difference_multi_variable( + order - 1, + func, + idx_to_derivate, + &f0_point, + self.step_size_multiplier * step_size, + ); let mut f1_point = *point; - f1_point[idx_to_derivate[order - 1]] = f1_point[idx_to_derivate[order - 1]] + T::from(step_size).unwrap(); - - let f1 = self.get_central_difference_multi_variable(order - 1, func, idx_to_derivate, &f1_point, self.step_size_multiplier*step_size); - - return (f1 - f0)/(T::from(2.0*step_size).unwrap()); + f1_point[idx_to_derivate[order - 1]] = + f1_point[idx_to_derivate[order - 1]] + T::from(step_size).unwrap(); + + let f1 = self.get_central_difference_multi_variable( + order - 1, + func, + idx_to_derivate, + &f1_point, + self.step_size_multiplier * step_size, + ); + + return (f1 - f0) / (T::from(2.0 * step_size).unwrap()); } } -impl DerivatorMultiVariable for MultiVariableSolver -{ +impl DerivatorMultiVariable for MultiVariableSolver { /// Returns the numerical differentiation value for a multi variable function /// order: number of times the equation should be differentiated /// func: the multi variable function /// idx_to_derivate: The variable index/indices whose respect to we want to differentiate /// point: the point of interest around which we want to differentiate - /// + /// /// NOTE: Returns a Result /// Possible &'static str are: /// NUMBER_OF_DERIVATIVE_STEPS_CANNOT_BE_ZERO -> if the step size value is zero /// DERIVATE_ORDER_CANNOT_BE_ZERO -> if the 'order' argument is zero /// INDEX_TO_DERIVATE_ILL_FORMED -> if size of 'idx_to_derivate' argument is not equal to the 'order' argument - /// + /// /// assume we want to differentiate f(x,y,z) = y*sin(x) + x*cos(y) + x*y*e^z. the function would be: /// ``` - /// let my_func = | args: &[f64; 3] | -> f64 - /// { + /// let my_func = | args: &[f64; 3] | -> f64 + /// { /// return args[1]*args[0].sin() + args[0]*args[1].cos() + args[0]*args[1]*args[2].exp(); /// }; /// /// let point = [1.0, 2.0, 3.0]; //the point at which we want to differentiate - /// - /// + /// + /// /// use multicalc::numerical_derivative::derivator::*; /// use multicalc::numerical_derivative::finite_difference::*; - /// + /// /// let derivator = MultiVariableSolver::default(); - /// + /// /// let idx: [usize; 2] = [0, 1]; //mixed partial double derivate d(df/dx)/dy /// let val = derivator.get(2, &my_func, &idx, &point).unwrap(); /// let expected_value = f64::cos(1.0) - f64::sin(2.0) + f64::exp(3.0); /// assert!(f64::abs(val - expected_value) < 0.001); - /// - /// let idx: [usize; 2] = [1, 1]; //partial double derivative d(df/dy)/dy + /// + /// let idx: [usize; 2] = [1, 1]; //partial double derivative d(df/dy)/dy ///let val = derivator.get(2, &my_func, &idx, &point).unwrap(); ///let expected_value = -1.0*f64::cos(2.0); ///assert!(f64::abs(val - expected_value) < 0.0001); ///``` - fn get(&self, order: usize, func: &dyn Fn(&[T; NUM_VARS]) -> T, idx_to_derivate: &[usize; NUM_ORDER], point: &[T; NUM_VARS]) -> Result - { - if self.step_size == 0.0 - { + fn get( + &self, + order: usize, + func: &dyn Fn(&[T; NUM_VARS]) -> T, + idx_to_derivate: &[usize; NUM_ORDER], + point: &[T; NUM_VARS], + ) -> Result { + if self.step_size == 0.0 { return Err(NUMBER_OF_DERIVATIVE_STEPS_CANNOT_BE_ZERO); } - if order == 0 - { + if order == 0 { return Err(DERIVATE_ORDER_CANNOT_BE_ZERO); } - if order != NUM_ORDER - { + if order != NUM_ORDER { return Err(INDEX_TO_DERIVATE_ILL_FORMED); } - - for iter in 0..idx_to_derivate.len() - { - if idx_to_derivate[iter] >= point.len() - { + + for iter in 0..idx_to_derivate.len() { + if idx_to_derivate[iter] >= point.len() { return Err(INDEX_TO_DERIVATIVE_OUT_OF_RANGE); } } - match self.method - { - mode::FiniteDifferenceMode::Forward => return Ok(self.get_forward_difference_multi_variable(order, func, idx_to_derivate, point, self.step_size)), - mode::FiniteDifferenceMode::Backward => return Ok(self.get_backward_difference_multi_variable(order, func, idx_to_derivate, point, self.step_size)), - mode::FiniteDifferenceMode::Central => return Ok(self.get_central_difference_multi_variable(order, func, idx_to_derivate, point, self.step_size)) - } + match self.method { + mode::FiniteDifferenceMode::Forward => { + return Ok(self.get_forward_difference_multi_variable( + order, + func, + idx_to_derivate, + point, + self.step_size, + )) + } + mode::FiniteDifferenceMode::Backward => { + return Ok(self.get_backward_difference_multi_variable( + order, + func, + idx_to_derivate, + point, + self.step_size, + )) + } + mode::FiniteDifferenceMode::Central => { + return Ok(self.get_central_difference_multi_variable( + order, + func, + idx_to_derivate, + point, + self.step_size, + )) + } + } } -} \ No newline at end of file +} diff --git a/src/numerical_derivative/hessian.rs b/src/numerical_derivative/hessian.rs index a9d6ed7..a59db1f 100644 --- a/src/numerical_derivative/hessian.rs +++ b/src/numerical_derivative/hessian.rs @@ -4,75 +4,76 @@ use num_complex::ComplexFloat; ///computes the hessian matrix for a given function /// Can handle single and multivariable equations of any complexity or size -pub struct Hessian -{ - derivator: D +pub struct Hessian { + derivator: D, } -impl Default for Hessian -{ +impl Default for Hessian { ///the default constructor, optimal for most generic cases - fn default() -> Self - { - return Hessian { derivator: D::default() }; + fn default() -> Self { + return Hessian { + derivator: D::default(), + }; } } -impl Hessian -{ +impl Hessian { ///custom constructor, optimal for fine tuning /// You can create a custom multivariable derivator from this crate - /// or supply your own by implementing the base traits yourself - pub fn from_derivator(derivator: D) -> Self - { - return Hessian {derivator} + /// or supply your own by implementing the base traits yourself + pub fn from_derivator(derivator: D) -> Self { + return Hessian { derivator }; } /// Returns the hessian matrix for a given function /// Can handle multivariable functions of any order or complexity - /// - /// The 2-D matrix returned has the structure [[d2f/d2var1, d2f/dvar1*dvar2, ... , d2f/dvar1*dvarN], - /// [ ... ], + /// + /// The 2-D matrix returned has the structure [[d2f/d2var1, d2f/dvar1*dvar2, ... , d2f/dvar1*dvarN], + /// [ ... ], /// [d2f/dvar1*dvarN, d2f/dvar2*dvarN, ... , dfM/d2varN]] /// where 'N' is the total number of variables - /// + /// /// NOTE: Returns a Result /// Possible &'static str are: /// NUMBER_OF_DERIVATIVE_STEPS_CANNOT_BE_ZERO -> if the derivative step size is zero - /// + /// /// assume our function is y*sin(x) + 2*x*e^y. First define the function /// ``` /// use multicalc::numerical_derivative::finite_difference::MultiVariableSolver; /// use multicalc::numerical_derivative::hessian::Hessian; - /// let my_func = | args: &[f64; 2] | -> f64 - /// { + /// let my_func = | args: &[f64; 2] | -> f64 + /// { /// return args[1]*args[0].sin() + 2.0*args[0]*args[1].exp(); /// }; - /// + /// /// let points = [1.0, 2.0]; //the point around which we want the hessian matrix /// let hessian = Hessian::::default(); - /// + /// /// let result = hessian.get(&my_func, &points).unwrap(); /// ``` - /// - pub fn get(&self, function: &dyn Fn(&[T; NUM_VARS]) -> T, vector_of_points: &[T; NUM_VARS]) -> Result<[[T; NUM_VARS]; NUM_VARS], &'static str> - { + /// + pub fn get( + &self, + function: &dyn Fn(&[T; NUM_VARS]) -> T, + vector_of_points: &[T; NUM_VARS], + ) -> Result<[[T; NUM_VARS]; NUM_VARS], &'static str> { let mut result = [[T::from(f64::NAN).unwrap(); NUM_VARS]; NUM_VARS]; - for row_index in 0..NUM_VARS - { - for col_index in 0..NUM_VARS - { - if result[row_index][col_index].is_nan() - { - result[row_index][col_index] = self.derivator.get_double_partial(function, &[row_index, col_index], vector_of_points)?; + for row_index in 0..NUM_VARS { + for col_index in 0..NUM_VARS { + if result[row_index][col_index].is_nan() { + result[row_index][col_index] = self.derivator.get_double_partial( + function, + &[row_index, col_index], + vector_of_points, + )?; - result[col_index][row_index] = result[row_index][col_index]; //exploit the fact that a hessian is a symmetric matrix + result[col_index][row_index] = result[row_index][col_index]; + //exploit the fact that a hessian is a symmetric matrix } } } return Ok(result); } - -} \ No newline at end of file +} diff --git a/src/numerical_derivative/jacobian.rs b/src/numerical_derivative/jacobian.rs index cf53f0f..3c4ee65 100644 --- a/src/numerical_derivative/jacobian.rs +++ b/src/numerical_derivative/jacobian.rs @@ -1,4 +1,4 @@ -use crate::numerical_derivative::derivator::DerivatorMultiVariable; +use crate::numerical_derivative::derivator::DerivatorMultiVariable; use crate::utils::error_codes::*; use num_complex::ComplexFloat; @@ -6,104 +6,107 @@ use num_complex::ComplexFloat; #[cfg(feature = "heap")] use std::{boxed::Box, vec::Vec}; -pub struct Jacobian -{ - derivator: D +pub struct Jacobian { + derivator: D, } -impl Default for Jacobian -{ - fn default() -> Self - { - return Jacobian { derivator: D::default() }; +impl Default for Jacobian { + fn default() -> Self { + return Jacobian { + derivator: D::default(), + }; } } -impl Jacobian -{ +impl Jacobian { ///custom constructor, optimal for fine tuning /// You can create a custom multivariable derivator from this crate /// or supply your own by implementing the base traits yourself - pub fn from_derivator(derivator: D) -> Self - { - return Jacobian {derivator} + pub fn from_derivator(derivator: D) -> Self { + return Jacobian { derivator }; } /// Returns the jacobian matrix for a given vector of functions /// Can handle multivariable functions of any order or complexity - /// + /// /// The 2-D matrix returned has the structure [[df1/dvar1, df1/dvar2, ... , df1/dvarN], - /// [ ... ], + /// [ ... ], /// [dfM/dvar1, dfM/dvar2, ... , dfM/dvarN]] - /// + /// /// where 'N' is the total number of variables, and 'M' is the total number of functions - /// + /// /// NOTE: Returns a Result /// Possible &'static str are: /// VECTOR_OF_FUNCTIONS_CANNOT_BE_EMPTY -> if function_matrix argument is an empty array /// NUMBER_OF_DERIVATIVE_STEPS_CANNOT_BE_ZERO -> if the derivative step size is zero - /// + /// /// assume our function vector is (x*y*z , x^2 + y^2). First define both the functions /// ``` /// use multicalc::numerical_derivative::finite_difference::MultiVariableSolver; /// use multicalc::numerical_derivative::jacobian::Jacobian; - /// let my_func1 = | args: &[f64; 3] | -> f64 - /// { + /// let my_func1 = | args: &[f64; 3] | -> f64 + /// { /// return args[0]*args[1]*args[2]; //x*y*z /// }; - /// - /// let my_func2 = | args: &[f64; 3] | -> f64 - /// { + /// + /// let my_func2 = | args: &[f64; 3] | -> f64 + /// { /// return args[0].powf(2.0) + args[1].powf(2.0); //x^2 + y^2 /// }; - /// + /// /// //define the function vector /// let function_matrix: [&dyn Fn(&[f64; 3]) -> f64; 2] = [&my_func1, &my_func2]; /// let points = [1.0, 2.0, 3.0]; //the point around which we want the jacobian matrix - /// + /// /// let jacobian = Jacobian::::default(); /// let result = jacobian.get(&function_matrix, &points).unwrap(); /// ``` - /// - pub fn get(&self, function_matrix: &[&dyn Fn(&[T; NUM_VARS]) -> T; NUM_FUNCS], vector_of_points: &[T; NUM_VARS]) -> Result<[[T; NUM_VARS]; NUM_FUNCS], &'static str> - { - if function_matrix.is_empty() - { + /// + pub fn get( + &self, + function_matrix: &[&dyn Fn(&[T; NUM_VARS]) -> T; NUM_FUNCS], + vector_of_points: &[T; NUM_VARS], + ) -> Result<[[T; NUM_VARS]; NUM_FUNCS], &'static str> { + if function_matrix.is_empty() { return Err(VECTOR_OF_FUNCTIONS_CANNOT_BE_EMPTY); } let mut result = [[T::zero(); NUM_VARS]; NUM_FUNCS]; - for row_index in 0..NUM_FUNCS - { - for col_index in 0..NUM_VARS - { - result[row_index][col_index] = self.derivator.get_single_partial(&function_matrix[row_index], col_index, vector_of_points)?; + for row_index in 0..NUM_FUNCS { + for col_index in 0..NUM_VARS { + result[row_index][col_index] = self.derivator.get_single_partial( + &function_matrix[row_index], + col_index, + vector_of_points, + )?; } } - + return Ok(result); } /// same as [Jacobian::get] but uses heap-allocated vectors to generate the jacobian matrix. /// Useful when handling large datasets to avoid a stack overflow. To use, turn on the feature "heap" (false by default) /// Can handle multivariable functions of any order or complexity - /// + /// /// The 2-D matrix returned has the structure [[df1/dvar1, df1/dvar2, ... , df1/dvarN], - /// [ ... ], + /// [ ... ], /// [dfM/dvar1, dfM/dvar2, ... , dfM/dvarN]] - /// + /// /// where 'N' is the total number of variables, and 'M' is the total number of functions - /// + /// /// NOTE: Returns a Result /// Possible &'static str are: /// VectorOfFunctionsCannotBeEmpty -> if function_matrix argument is an empty array /// NumberOfStepsCannotBeZero -> if the derivative step size is zero #[cfg(feature = "heap")] - pub fn get_on_heap(&self, function_matrix: &Vec T>>, vector_of_points: &[T; NUM_VARS]) -> Result>, &'static str> - { - if function_matrix.is_empty() - { + pub fn get_on_heap( + &self, + function_matrix: &Vec T>>, + vector_of_points: &[T; NUM_VARS], + ) -> Result>, &'static str> { + if function_matrix.is_empty() { return Err(VECTOR_OF_FUNCTIONS_CANNOT_BE_EMPTY); } @@ -111,17 +114,19 @@ impl Jacobian let mut result: Vec> = Vec::new(); - for row_index in 0..num_funcs - { + for row_index in 0..num_funcs { let mut cur_row: Vec = Vec::new(); - for col_index in 0..NUM_VARS - { - cur_row.push(self.derivator.get_single_partial(&function_matrix[row_index], col_index, vector_of_points)?); + for col_index in 0..NUM_VARS { + cur_row.push(self.derivator.get_single_partial( + &function_matrix[row_index], + col_index, + vector_of_points, + )?); } result.push(cur_row); } - + return Ok(result); } -} \ No newline at end of file +} diff --git a/src/numerical_derivative/mod.rs b/src/numerical_derivative/mod.rs index f30f7e1..dd533cc 100644 --- a/src/numerical_derivative/mod.rs +++ b/src/numerical_derivative/mod.rs @@ -1,8 +1,8 @@ -pub mod mode; pub mod derivator; pub mod finite_difference; -pub mod jacobian; pub mod hessian; +pub mod jacobian; +pub mod mode; #[cfg(test)] -mod test; \ No newline at end of file +mod test; diff --git a/src/numerical_derivative/mode.rs b/src/numerical_derivative/mode.rs index b0d5cfa..542838e 100644 --- a/src/numerical_derivative/mode.rs +++ b/src/numerical_derivative/mode.rs @@ -1,15 +1,13 @@ - //In most cases, Central is recommended for the highest accuracy //If you feel unsure, start with Central and then tweak depending on results //Not that the accuracy of results also depend on the step size #[derive(Debug, Copy, Clone)] -pub enum FiniteDifferenceMode -{ +pub enum FiniteDifferenceMode { Forward, Backward, - Central + Central, } ///constants used by finite_difference module pub const DEFAULT_STEP_SIZE: f64 = 1.0e-5; -pub const DEFAULT_STEP_SIZE_MULTIPLIER: f64 = 10.0; \ No newline at end of file +pub const DEFAULT_STEP_SIZE_MULTIPLIER: f64 = 10.0; diff --git a/src/numerical_derivative/test.rs b/src/numerical_derivative/test.rs index c518c82..c8e28de 100644 --- a/src/numerical_derivative/test.rs +++ b/src/numerical_derivative/test.rs @@ -10,14 +10,11 @@ use crate::utils::error_codes::*; #[cfg(feature = "heap")] use std::{boxed::Box, vec::Vec}; - #[test] -fn test_single_derivative_forward_difference() -{ +fn test_single_derivative_forward_difference() { //function is x*x/2.0, derivative is known to be x - let func = | args: f64 | -> f64 - { - return args*args/2.0; + let func = |args: f64| -> f64 { + return args * args / 2.0; }; //simple derivative around x = 2.0, expect a value of 2.00 @@ -30,12 +27,10 @@ fn test_single_derivative_forward_difference() } #[test] -fn test_single_derivative_backward_difference() -{ +fn test_single_derivative_backward_difference() { //function is x*x/2.0, derivative is known to be x - let func = | args: f64 | -> f64 - { - return args*args/2.0; + let func = |args: f64| -> f64 { + return args * args / 2.0; }; let mut derivator = SingleVariableSolver::default(); @@ -46,12 +41,10 @@ fn test_single_derivative_backward_difference() } #[test] -fn test_single_derivative_central_difference() -{ +fn test_single_derivative_central_difference() { //function is x*x/2.0, derivative is known to be x - let func = | args: f64 | -> f64 - { - return args*args/2.0; + let func = |args: f64| -> f64 { + return args * args / 2.0; }; let mut derivator = SingleVariableSolver::default(); @@ -63,12 +56,10 @@ fn test_single_derivative_central_difference() } #[test] -fn test_single_derivative_partial_1() -{ +fn test_single_derivative_partial_1() { //function is 3*x*x + 2*x*y - let func = | args: &[f64; 2] | -> f64 - { - return 3.0*args[0]*args[0] + 2.0*args[0]*args[1]; + let func = |args: &[f64; 2]| -> f64 { + return 3.0 * args[0] * args[0] + 2.0 * args[0] * args[1]; }; let point = [1.0, 3.0]; @@ -86,12 +77,12 @@ fn test_single_derivative_partial_1() } #[test] -fn test_single_derivative_partial_2() -{ +fn test_single_derivative_partial_2() { //function is y*sin(x) + x*cos(y) + x*y*e^z - let func = | args: &[f64; 3] | -> f64 - { - return args[1]*args[0].sin() + args[0]*args[1].cos() + args[0]*args[1]*args[2].exp(); + let func = |args: &[f64; 3]| -> f64 { + return args[1] * args[0].sin() + + args[0] * args[1].cos() + + args[0] * args[1] * args[2].exp(); }; let point = [1.0, 2.0, 3.0]; @@ -101,33 +92,33 @@ fn test_single_derivative_partial_2() //partial derivate for (x, y, z) = (1.0, 2.0, 3.0), partial derivative for x is known to be y*cos(x) + cos(y) + y*e^z let val = derivator.get_single_partial(&func, 0, &point).unwrap(); - let expected_value = 2.0*f64::cos(1.0) + f64::cos(2.0) + 2.0*f64::exp(3.0); + let expected_value = 2.0 * f64::cos(1.0) + f64::cos(2.0) + 2.0 * f64::exp(3.0); assert!(f64::abs(val - expected_value) < 0.000001); //partial derivate for (x, y, z) = (1.0, 2.0, 3.0), partial derivative for y is known to be sin(x) - x*sin(y) + x*e^z let val = derivator.get_single_partial(&func, 1, &point).unwrap(); - let expected_value = f64::sin(1.0) - 1.0*f64::sin(2.0) + 1.0*f64::exp(3.0); + let expected_value = f64::sin(1.0) - 1.0 * f64::sin(2.0) + 1.0 * f64::exp(3.0); assert!(f64::abs(val - expected_value) < 0.000001); //partial derivate for (x, y, z) = (1.0, 2.0, 3.0), partial derivative for z is known to be x*y*e^z let val = derivator.get_single_partial(&func, 2, &point).unwrap(); - let expected_value = 1.0*2.0*f64::exp(3.0); + let expected_value = 1.0 * 2.0 * f64::exp(3.0); assert!(f64::abs(val - expected_value) < 0.00001); } #[test] -fn test_single_derivative_error_1() -{ +fn test_single_derivative_error_1() { //function is y*sin(x) + x*cos(y) + x*y*e^z - let func = | args: &[f64; 3] | -> f64 - { - return args[1]*args[0].sin() + args[0]*args[1].cos() + args[0]*args[1]*args[2].exp(); + let func = |args: &[f64; 3]| -> f64 { + return args[1] * args[0].sin() + + args[0] * args[1].cos() + + args[0] * args[1] * args[2].exp(); }; let point = [1.0, 2.0, 3.0]; let derivator = MultiVariableSolver::from_parameters(0.0, FiniteDifferenceMode::Central, 1.0); - + //expect failure because step size is zero let result = derivator.get(1, &func, &[0], &point); assert!(result.is_err()); @@ -135,18 +126,18 @@ fn test_single_derivative_error_1() } #[test] -fn test_single_derivative_error_2() -{ +fn test_single_derivative_error_2() { //function is y*sin(x) + x*cos(y) + x*y*e^z - let func = | args: &[f64; 3] | -> f64 - { - return args[1]*args[0].sin() + args[0]*args[1].cos() + args[0]*args[1]*args[2].exp(); + let func = |args: &[f64; 3]| -> f64 { + return args[1] * args[0].sin() + + args[0] * args[1].cos() + + args[0] * args[1] * args[2].exp(); }; let point = [1.0, 2.0, 3.0]; let derivator = MultiVariableSolver::default(); - + //expect failure because idx_to_derivate is greater than the number of points let result = derivator.get(1, &func, &[0; 4], &point); assert!(result.is_err()); @@ -154,18 +145,18 @@ fn test_single_derivative_error_2() } #[test] -fn test_single_derivative_error_3() -{ +fn test_single_derivative_error_3() { //function is y*sin(x) + x*cos(y) + x*y*e^z - let func = | args: &[f64; 3] | -> f64 - { - return args[1]*args[0].sin() + args[0]*args[1].cos() + args[0]*args[1]*args[2].exp(); + let func = |args: &[f64; 3]| -> f64 { + return args[1] * args[0].sin() + + args[0] * args[1].cos() + + args[0] * args[1] * args[2].exp(); }; let point = [1.0, 2.0, 3.0]; let derivator = MultiVariableSolver::default(); - + //expect failure because order is zero let result = derivator.get(0, &func, &[0; 2], &point); assert!(result.is_err()); @@ -173,18 +164,18 @@ fn test_single_derivative_error_3() } #[test] -fn test_single_derivative_error_4() -{ +fn test_single_derivative_error_4() { //function is y*sin(x) + x*cos(y) + x*y*e^z - let func = | args: &[f64; 3] | -> f64 - { - return args[1]*args[0].sin() + args[0]*args[1].cos() + args[0]*args[1]*args[2].exp(); + let func = |args: &[f64; 3]| -> f64 { + return args[1] * args[0].sin() + + args[0] * args[1].cos() + + args[0] * args[1] * args[2].exp(); }; let point = [1.0, 2.0, 3.0]; let derivator = MultiVariableSolver::default(); - + //TODO description let result = derivator.get(5, &func, &[0; 2], &point); assert!(result.is_err()); @@ -192,12 +183,10 @@ fn test_single_derivative_error_4() } #[test] -fn test_double_derivative_forward_difference() -{ +fn test_double_derivative_forward_difference() { //function is x*Sin(x), double derivative known to be 2.0*Cos(x) - x*Sin(x) - let func = | args:f64 | -> f64 - { - return args*args.sin(); + let func = |args: f64| -> f64 { + return args * args.sin(); }; let mut derivator = SingleVariableSolver::default(); @@ -205,17 +194,15 @@ fn test_double_derivative_forward_difference() //double derivative at x = 1.0 let val = derivator.get(2, &func, 1.0).unwrap(); - let expected_val = 2.0*f64::cos(1.0) - 1.0*f64::sin(1.0); + let expected_val = 2.0 * f64::cos(1.0) - 1.0 * f64::sin(1.0); assert!(f64::abs(val - expected_val) < 0.05); } #[test] -fn test_double_derivative_backward_difference() -{ +fn test_double_derivative_backward_difference() { //function is x*Sin(x), double derivative known to be 2.0*Cos(x) - x*Sin(x) - let func = | args:f64 | -> f64 - { - return args*args.sin(); + let func = |args: f64| -> f64 { + return args * args.sin(); }; let mut derivator = SingleVariableSolver::default(); @@ -223,17 +210,15 @@ fn test_double_derivative_backward_difference() //double derivative at x = 1.0 let val = derivator.get(2, &func, 1.0).unwrap(); - let expected_val = 2.0*f64::cos(1.0) - 1.0*f64::sin(1.0); + let expected_val = 2.0 * f64::cos(1.0) - 1.0 * f64::sin(1.0); assert!(f64::abs(val - expected_val) < 0.05); } #[test] -fn test_double_derivative_central_difference() -{ +fn test_double_derivative_central_difference() { //function is x*Sin(x), double derivative known to be 2.0*Cos(x) - x*Sin(x) - let func = | args:f64 | -> f64 - { - return args*args.sin(); + let func = |args: f64| -> f64 { + return args * args.sin(); }; let mut derivator = SingleVariableSolver::default(); @@ -241,49 +226,49 @@ fn test_double_derivative_central_difference() //double derivative at x = 1.0 let val = derivator.get(2, &func, 1.0).unwrap(); - let expected_val = 2.0*f64::cos(1.0) - 1.0*f64::sin(1.0); + let expected_val = 2.0 * f64::cos(1.0) - 1.0 * f64::sin(1.0); assert!(f64::abs(val - expected_val) < 0.00001); } #[test] -fn test_double_derivative_partial_1() -{ +fn test_double_derivative_partial_1() { //function is y*sin(x) + x*cos(y) + x*y*e^z - let func = | args: &[f64; 3] | -> f64 - { - return args[1]*args[0].sin() + args[0]*args[1].cos() + args[0]*args[1]*args[2].exp(); + let func = |args: &[f64; 3]| -> f64 { + return args[1] * args[0].sin() + + args[0] * args[1].cos() + + args[0] * args[1] * args[2].exp(); }; let point = [1.0, 2.0, 3.0]; let derivator = MultiVariableSolver::default(); - let idx: [usize; 2] = [0, 0]; + let idx: [usize; 2] = [0, 0]; //partial derivate for (x, y, z) = (1.0, 2.0, 3.0), partial double derivative for x is known to be -y*sin(x) let val = derivator.get(2, &func, &idx, &point).unwrap(); - let expected_value = -2.0*f64::sin(1.0); + let expected_value = -2.0 * f64::sin(1.0); assert!(f64::abs(val - expected_value) < 0.0001); let idx: [usize; 2] = [1, 1]; //partial derivate for (x, y, z) = (1.0, 2.0, 3.0), partial double derivative for y is known to be -x*cos(y) let val = derivator.get(2, &func, &idx, &point).unwrap(); - let expected_value = -1.0*f64::cos(2.0); + let expected_value = -1.0 * f64::cos(2.0); assert!(f64::abs(val - expected_value) < 0.0001); let idx: [usize; 2] = [2, 2]; //partial derivate for (x, y, z) = (1.0, 2.0, 3.0), partial double derivative for z is known to be x*y*e^z let val = derivator.get(2, &func, &idx, &point).unwrap(); - let expected_value = 1.0*2.0*f64::exp(3.0); + let expected_value = 1.0 * 2.0 * f64::exp(3.0); assert!(f64::abs(val - expected_value) < 0.0001); } #[test] -fn test_double_derivative_partial_2() -{ +fn test_double_derivative_partial_2() { //function is y*sin(x) + x*cos(y) + x*y*e^z - let func = | args: &[f64; 3] | -> f64 - { - return args[1]*args[0].sin() + args[0]*args[1].cos() + args[0]*args[1]*args[2].exp(); + let func = |args: &[f64; 3]| -> f64 { + return args[1] * args[0].sin() + + args[0] * args[1].cos() + + args[0] * args[1] * args[2].exp(); }; let point = [1.0, 2.0, 3.0]; @@ -291,31 +276,28 @@ fn test_double_derivative_partial_2() let derivator = MultiVariableSolver::default(); let idx: [usize; 2] = [0, 1]; //mixed partial double derivate d(df/dx)/dy - //partial derivate for (x, y, z) = (1.0, 2.0, 3.0), mixed partial double derivative is known to be cos(x) - sin(y) + e^z + //partial derivate for (x, y, z) = (1.0, 2.0, 3.0), mixed partial double derivative is known to be cos(x) - sin(y) + e^z let val = derivator.get(2, &func, &idx, &point).unwrap(); let expected_value = f64::cos(1.0) - f64::sin(2.0) + f64::exp(3.0); assert!(f64::abs(val - expected_value) < 0.001); let idx: [usize; 2] = [1, 2]; //mixed partial double derivate d(df/dy)/dz - //partial derivate for (x, y, z) = (1.0, 2.0, 3.0), mixed partial double derivative is known to be x*e^z + //partial derivate for (x, y, z) = (1.0, 2.0, 3.0), mixed partial double derivative is known to be x*e^z let val = derivator.get(2, &func, &idx, &point).unwrap(); - let expected_value = 1.0*f64::exp(3.0); + let expected_value = 1.0 * f64::exp(3.0); assert!(f64::abs(val - expected_value) < 0.001); let idx: [usize; 2] = [0, 2]; //mixed partial double derivate d(df/dx)/dz - //partial derivate for (x, y, z) = (1.0, 2.0, 3.0), mixed partial double derivative is known to be y*e^z + //partial derivate for (x, y, z) = (1.0, 2.0, 3.0), mixed partial double derivative is known to be y*e^z let val = derivator.get(2, &func, &idx, &point).unwrap(); - let expected_value = 2.0*f64::exp(3.0); + let expected_value = 2.0 * f64::exp(3.0); assert!(f64::abs(val - expected_value) < 0.001); } - #[test] -fn test_triple_derivative_forward_difference() -{ +fn test_triple_derivative_forward_difference() { //function is x^4, triple derivative is known to be 24.0*x - let func = | args: f64 | -> f64 - { + let func = |args: f64| -> f64 { return args.powf(4.0); }; @@ -328,11 +310,9 @@ fn test_triple_derivative_forward_difference() } #[test] -fn test_triple_derivative_backward_difference() -{ +fn test_triple_derivative_backward_difference() { //function is x^4, triple derivative is known to be 24.0*x - let func = | args: f64 | -> f64 - { + let func = |args: f64| -> f64 { return args.powf(4.0); }; @@ -345,11 +325,9 @@ fn test_triple_derivative_backward_difference() } #[test] -fn test_triple_derivative_central_difference() -{ +fn test_triple_derivative_central_difference() { //function is x^4, triple derivative is known to be 24.0*x - let func = | args: f64 | -> f64 - { + let func = |args: f64| -> f64 { return args.powf(4.0); }; @@ -362,12 +340,10 @@ fn test_triple_derivative_central_difference() } #[test] -fn test_triple_derivative_partial_1() -{ +fn test_triple_derivative_partial_1() { //function is y*sin(x) + 2*x*e^y - let func = | args: &[f64; 2] | -> f64 - { - return args[1]*args[0].sin() + 2.0*args[0]*args[1].exp(); + let func = |args: &[f64; 2]| -> f64 { + return args[1] * args[0].sin() + 2.0 * args[0] * args[1].exp(); }; let point = [1.0, 3.0]; @@ -377,23 +353,21 @@ fn test_triple_derivative_partial_1() let idx = [0, 0, 0]; //partial derivate for (x, y) = (1.0, 3.0), partial triple derivative for x is known to be -y*cos(x) let val = derivator.get(3, &func, &idx, &point).unwrap(); - let expected_val = -3.0*f64::cos(1.0); + let expected_val = -3.0 * f64::cos(1.0); assert!(f64::abs(val - expected_val) < 0.001); let idx = [1, 1, 1]; //partial derivate for (x, y) = (1.0, 3.0), partial triple derivative for y is known to be 2*x*e^y let val = derivator.get(3, &func, &idx, &point).unwrap(); - let expected_val = 2.0*1.0*f64::exp(3.0); + let expected_val = 2.0 * 1.0 * f64::exp(3.0); assert!(f64::abs(val - expected_val) < 0.001); } #[test] -fn test_triple_derivative_partial_2() -{ +fn test_triple_derivative_partial_2() { //function is x^3 * y^3 * z^3 - let func = | args: &[f64; 3] | -> f64 - { - return args[0].powf(3.0)*args[1].powf(3.0)*args[2].powf(3.0); + let func = |args: &[f64; 3]| -> f64 { + return args[0].powf(3.0) * args[1].powf(3.0) * args[2].powf(3.0); }; let point = [1.0, 2.0, 3.0]; @@ -401,28 +375,25 @@ fn test_triple_derivative_partial_2() let derivator = MultiVariableSolver::default(); let idx = [0, 1, 2]; //mixed partial double derivate d(d(df/dx)/dy)/dz - //partial derivate for (x, y) = (1.0, 2.0, 3.0), mixed partial triple derivative is known to be 27.0*x^2*y^2*z^2 + //partial derivate for (x, y) = (1.0, 2.0, 3.0), mixed partial triple derivative is known to be 27.0*x^2*y^2*z^2 let val = derivator.get(3, &func, &idx, &point).unwrap(); assert!(f64::abs(val - 972.0) < 0.01); let idx = [0, 1, 1]; //mixed partial double derivate d(d(df/dx)/dy)/dy - //partial derivate for (x, y) = (1.0, 2.0, 3.0), mixed partial triple derivative for y is known to be 18*x^2*y*z^3 + //partial derivate for (x, y) = (1.0, 2.0, 3.0), mixed partial triple derivative for y is known to be 18*x^2*y*z^3 let val = derivator.get(3, &func, &idx, &point).unwrap(); assert!(f64::abs(val - 972.0) < 0.01); } #[test] -fn test_jacobian_1() -{ +fn test_jacobian_1() { //function is x*y*z - let func1 = | args: &[f64; 3] | -> f64 - { - return args[0]*args[1]*args[2]; + let func1 = |args: &[f64; 3]| -> f64 { + return args[0] * args[1] * args[2]; }; //function is x^2 + y^2 - let func2 = | args: &[f64; 3] | -> f64 - { + let func2 = |args: &[f64; 3]| -> f64 { return args[0].powf(2.0) + args[1].powf(2.0); }; @@ -439,33 +410,28 @@ fn test_jacobian_1() let expected_result = [[6.0, 3.0, 2.0], [2.0, 4.0, 0.0]]; - for i in 0..function_matrix.len() - { - for j in 0..points.len() - { + for i in 0..function_matrix.len() { + for j in 0..points.len() { assert!(f64::abs(result[i][j] - expected_result[i][j]) < 0.000001); } } } - #[test] #[cfg(feature = "heap")] -fn test_jacobian_2() -{ +fn test_jacobian_2() { //function is x*y*z - let func1 = | args: &[f64; 3] | -> f64 - { - return args[0]*args[1]*args[2]; + let func1 = |args: &[f64; 3]| -> f64 { + return args[0] * args[1] * args[2]; }; //function is x^2 + y^2 - let func2 = | args: &[f64; 3] | -> f64 - { + let func2 = |args: &[f64; 3]| -> f64 { return args[0].powf(2.0) + args[1].powf(2.0); }; - let function_matrix: Vec f64>> = std::vec![Box::new(func1), Box::new(func2)]; + let function_matrix: Vec f64>> = + std::vec![Box::new(func1), Box::new(func2)]; let points = [1.0, 2.0, 3.0]; //the point around which we want the jacobian matrix @@ -478,18 +444,15 @@ fn test_jacobian_2() let expected_result = [[6.0, 3.0, 2.0], [2.0, 4.0, 0.0]]; - for i in 0..function_matrix.len() - { - for j in 0..points.len() - { + for i in 0..function_matrix.len() { + for j in 0..points.len() { assert!(f64::abs(result[i][j] - expected_result[i][j]) < 0.000001); } } } #[test] -fn test_jacobian_1_error() -{ +fn test_jacobian_1_error() { let function_matrix = []; //the point around which we want the jacobian matrix @@ -505,12 +468,10 @@ fn test_jacobian_1_error() } #[test] -fn test_hessian_1() -{ +fn test_hessian_1() { //function is y*sin(x) + 2*x*e^y - let func = | args: &[f64; 2] | -> f64 - { - return args[1]*args[0].sin() + 2.0*args[0]*args[1].exp(); + let func = |args: &[f64; 2]| -> f64 { + return args[1] * args[0].sin() + 2.0 * args[0] * args[1].exp(); }; let points = [1.0, 2.0]; //the point around which we want the hessian matrix @@ -522,14 +483,14 @@ fn test_hessian_1() assert!(result.len() == points.len()); //number of rows assert!(result[0].len() == points.len()); //number of columns - let expected_result = [[-2.0*f64::sin(1.0), f64::cos(1.0) + 2.0*f64::exp(2.0)], - [f64::cos(1.0) + 2.0*f64::exp(2.0), 2.0*f64::exp(2.0)]]; + let expected_result = [ + [-2.0 * f64::sin(1.0), f64::cos(1.0) + 2.0 * f64::exp(2.0)], + [f64::cos(1.0) + 2.0 * f64::exp(2.0), 2.0 * f64::exp(2.0)], + ]; - for i in 0..points.len() - { - for j in 0..points.len() - { + for i in 0..points.len() { + for j in 0..points.len() { assert!(f64::abs(result[i][j] - expected_result[i][j]) < 1e-5); } } -} \ No newline at end of file +} diff --git a/src/numerical_integration/gaussian_integration.rs b/src/numerical_integration/gaussian_integration.rs index 27c23b6..1ebb99c 100644 --- a/src/numerical_integration/gaussian_integration.rs +++ b/src/numerical_integration/gaussian_integration.rs @@ -1,146 +1,146 @@ -use crate::numerical_integration::mode::GaussianQuadratureMethod; -use crate::utils::{gh_table, gl_table, gauss_laguerre_table}; use crate::numerical_integration::integrator::*; +use crate::numerical_integration::mode::GaussianQuadratureMethod; use crate::utils::error_codes::*; - +use crate::utils::{gauss_laguerre_table, gh_table, gl_table}; pub const DEFAULT_QUADRATURE_ORDERS: usize = 4; ///Implements the gaussian quadrature methods for numerical integration for single variable functions #[derive(Clone, Copy)] -pub struct SingleVariableSolver -{ +pub struct SingleVariableSolver { order: usize, - integration_method: GaussianQuadratureMethod + integration_method: GaussianQuadratureMethod, } -impl Default for SingleVariableSolver -{ +impl Default for SingleVariableSolver { ///default constructor, optimal for most generic polynomial equations - fn default() -> Self - { - return SingleVariableSolver { order: DEFAULT_QUADRATURE_ORDERS, integration_method: GaussianQuadratureMethod::GaussLegendre }; + fn default() -> Self { + return SingleVariableSolver { + order: DEFAULT_QUADRATURE_ORDERS, + integration_method: GaussianQuadratureMethod::GaussLegendre, + }; } } -impl SingleVariableSolver -{ +impl SingleVariableSolver { ///returns the chosen number of nodes/order for quadrature - pub fn get_order(&self) -> usize - { + pub fn get_order(&self) -> usize { return self.order; } ///sets the number of nodes/order for quadrature - pub fn set_order(&mut self, order: usize) - { + pub fn set_order(&mut self, order: usize) { self.order = order; } ///returns the chosen integration method /// possible choices are GaussLegendre, GaussHermite and GaussLaguerre - pub fn get_integration_method(&self) -> GaussianQuadratureMethod - { + pub fn get_integration_method(&self) -> GaussianQuadratureMethod { return self.integration_method; } /// sets the integration method /// possible choices are GaussLegendre, GaussHermite and GaussLaguerre - pub fn set_integration_method(&mut self, integration_method: GaussianQuadratureMethod) - { + pub fn set_integration_method(&mut self, integration_method: GaussianQuadratureMethod) { self.integration_method = integration_method; } ///custom constructor, optimal for fine-tuning for specific cases - pub fn from_parameters(order: usize, integration_method: GaussianQuadratureMethod) -> Self - { - SingleVariableSolver - { + pub fn from_parameters(order: usize, integration_method: GaussianQuadratureMethod) -> Self { + SingleVariableSolver { order: order, - integration_method: integration_method - } + integration_method: integration_method, + } } ///Helper method to check if inputs are well defined - fn check_for_errors(&self, number_of_integrations: usize, integration_limit: &[[f64; 2]; NUM_INTEGRATIONS]) -> Result<(), &'static str> - { + fn check_for_errors( + &self, + number_of_integrations: usize, + integration_limit: &[[f64; 2]; NUM_INTEGRATIONS], + ) -> Result<(), &'static str> { //TODO - if !(1..=gl_table::MAX_GL_ORDER).contains(&self.order) - { + if !(1..=gl_table::MAX_GL_ORDER).contains(&self.order) { return Err(GAUSSIAN_QUADRATURE_ORDER_OUT_OF_RANGE); } - for iter in 0..integration_limit.len() - { - if integration_limit[iter][0] >= integration_limit[iter][1] - { + for iter in 0..integration_limit.len() { + if integration_limit[iter][0] >= integration_limit[iter][1] { return Err(INTEGRATION_LIMITS_ILL_DEFINED); } } - if NUM_INTEGRATIONS != number_of_integrations - { - return Err(INCORRECT_NUMBER_OF_INTEGRATION_LIMITS) - } + if NUM_INTEGRATIONS != number_of_integrations { + return Err(INCORRECT_NUMBER_OF_INTEGRATION_LIMITS); + } - return Ok(()); + return Ok(()); } ///returns the gauss legendre numerical integral for a given equation /// number_of_integrations: number of integrations to perform on the equation /// func: the equation to integrate /// integration_limit: the integration bound(s) for each round of integration - fn get_gauss_legendre(&self, number_of_integrations: usize, func: &dyn Fn(f64) -> f64, integration_limit: &[[f64; 2]; NUM_INTEGRATIONS]) -> f64 - { - if number_of_integrations == 1 - { + fn get_gauss_legendre( + &self, + number_of_integrations: usize, + func: &dyn Fn(f64) -> f64, + integration_limit: &[[f64; 2]; NUM_INTEGRATIONS], + ) -> f64 { + if number_of_integrations == 1 { let mut ans = 0.0; - let abcsissa_coeff = (integration_limit[0][1] - integration_limit[0][0])/2.0; - let intercept = (integration_limit[0][1] + integration_limit[0][0])/2.0; + let abcsissa_coeff = (integration_limit[0][1] - integration_limit[0][0]) / 2.0; + let intercept = (integration_limit[0][1] + integration_limit[0][0]) / 2.0; - for iter in 0..self.order - { - let (abcsissa, weight) = gl_table::get_gl_weights_and_abscissae(self.order, iter).unwrap(); + for iter in 0..self.order { + let (abcsissa, weight) = + gl_table::get_gl_weights_and_abscissae(self.order, iter).unwrap(); - let args = abcsissa_coeff*abcsissa + intercept; + let args = abcsissa_coeff * abcsissa + intercept; - ans = ans + weight*func(args); + ans = ans + weight * func(args); } - return abcsissa_coeff*ans; + return abcsissa_coeff * ans; } let mut ans = 0.0; - let abcsissa_coeff = (integration_limit[number_of_integrations-1][1] - integration_limit[number_of_integrations-1][0])/2.0; + let abcsissa_coeff = (integration_limit[number_of_integrations - 1][1] + - integration_limit[number_of_integrations - 1][0]) + / 2.0; //let intercept = (integration_limit[number_of_integrations-1][1] + integration_limit[number_of_integrations-1][0])/2.0; - for iter in 0..self.order - { + for iter in 0..self.order { let (_, weight) = gl_table::get_gl_weights_and_abscissae(self.order, iter).unwrap(); //let args = abcsissa_coeff*abcsissa + intercept; - ans = ans + weight*self.get_gauss_legendre(number_of_integrations-1, func, integration_limit); + ans = ans + + weight + * self.get_gauss_legendre(number_of_integrations - 1, func, integration_limit); } - return abcsissa_coeff*ans; + return abcsissa_coeff * ans; } ///returns the gauss hermite numerical integral for a given equation /// number_of_integrations: number of integrations to perform on the equation /// func: the equation to integrate /// integration_limit: the integration bound(s) for each round of integration - fn get_gauss_hermite(&self, number_of_integrations: usize, func: &dyn Fn(f64) -> f64, integration_limit: &[[f64; 2]; NUM_INTEGRATIONS]) -> f64 - { - if number_of_integrations == 1 - { + fn get_gauss_hermite( + &self, + number_of_integrations: usize, + func: &dyn Fn(f64) -> f64, + integration_limit: &[[f64; 2]; NUM_INTEGRATIONS], + ) -> f64 { + if number_of_integrations == 1 { let mut ans = 0.0; - for iter in 0..self.order - { - let (abcsissa, weight) = gh_table::get_gh_weights_and_abscissae(self.order, iter).unwrap(); + for iter in 0..self.order { + let (abcsissa, weight) = + gh_table::get_gh_weights_and_abscissae(self.order, iter).unwrap(); - ans = ans + weight*func(abcsissa)*f64::exp(abcsissa*abcsissa); + ans = ans + weight * func(abcsissa) * f64::exp(abcsissa * abcsissa); } return ans; @@ -148,11 +148,12 @@ impl SingleVariableSolver let mut ans = 0.0; - for iter in 0..self.order - { + for iter in 0..self.order { let (_, weight) = gh_table::get_gh_weights_and_abscissae(self.order, iter).unwrap(); - ans = ans + weight*self.get_gauss_hermite(number_of_integrations-1, func, integration_limit); + ans = ans + + weight + * self.get_gauss_hermite(number_of_integrations - 1, func, integration_limit); } return ans; @@ -162,16 +163,22 @@ impl SingleVariableSolver /// number_of_integrations: number of integrations to perform on the equation /// func: the equation to integrate /// integration_limit: the integration bound(s) for each round of integration - fn get_gauss_laguerre(&self, number_of_integrations: usize, func: &dyn Fn(f64) -> f64, integration_limit: &[[f64; 2]; NUM_INTEGRATIONS]) -> f64 - { - if number_of_integrations == 1 - { + fn get_gauss_laguerre( + &self, + number_of_integrations: usize, + func: &dyn Fn(f64) -> f64, + integration_limit: &[[f64; 2]; NUM_INTEGRATIONS], + ) -> f64 { + if number_of_integrations == 1 { let mut ans = 0.0; - for iter in 0..self.order - { - let (abcsissa, weight) = gauss_laguerre_table::get_gauss_laguerre_weights_and_abscissae(self.order, iter).unwrap(); - ans = ans + (weight*func(abcsissa)*f64::exp(abcsissa)); + for iter in 0..self.order { + let (abcsissa, weight) = + gauss_laguerre_table::get_gauss_laguerre_weights_and_abscissae( + self.order, iter, + ) + .unwrap(); + ans = ans + (weight * func(abcsissa) * f64::exp(abcsissa)); } return ans; @@ -179,142 +186,143 @@ impl SingleVariableSolver let mut ans = 0.0; - for iter in 0..self.order - { - let (_, weight) = gauss_laguerre_table::get_gauss_laguerre_weights_and_abscissae(self.order, iter).unwrap(); + for iter in 0..self.order { + let (_, weight) = + gauss_laguerre_table::get_gauss_laguerre_weights_and_abscissae(self.order, iter) + .unwrap(); //let args = (integration_limit[0][0] - integration_limit[0][1])*T::log(abcsissa - integration_limit[0][1], T::abs(T::exp(T::one()))) - abcsissa; - ans = ans + weight*self.get_gauss_laguerre(number_of_integrations, func, integration_limit); + ans = ans + + weight * self.get_gauss_laguerre(number_of_integrations, func, integration_limit); } return ans; } } -impl IntegratorSingleVariable for SingleVariableSolver -{ +impl IntegratorSingleVariable for SingleVariableSolver { ///returns the gaussian quadrature numerical integration for a single variable equation /// number_of_integrations: number of integrations to perform on the equation /// func: the equation to integrate /// integration_limit: the integration bound(s) for each round of integration - /// + /// /// NOTE: Returns a Result, where possible Err are: /// GAUSSIAN_QUADRATURE_ORDER_OUT_OF_RANGE -> if the chosen numer of nodes/order is out of supported range /// INTEGRATION_LIMITS_ILL_DEFINED -> if any integration_limit[i][0] >= integration_limit[i][1] for all possible i /// INCORRECT_NUMBER_OF_INTEGRATION_LIMITS -> if number_of_integrations is not equal to the size of integration_limit - /// + /// /// assume we want to differentiate f(x) = 4.0*x*x*x - 3.0*x*x. the function would be: /// ``` - /// let my_func = | arg: f64 | -> f64 - /// { + /// let my_func = | arg: f64 | -> f64 + /// { /// return 4.0*arg*arg*arg - 3.0*arg*arg; /// }; - /// + /// /// use multicalc::numerical_integration::integrator::*; /// use multicalc::numerical_integration::gaussian_integration; - /// + /// /// let integrator = gaussian_integration::SingleVariableSolver::default(); /// let integration_limit = [[0.0, 2.0]; 1]; /// let val = integrator.get(1, &my_func, &integration_limit).unwrap(); //single integration /// assert!(f64::abs(val - 8.0) < 1e-7); - /// + /// /// let integration_limit = [[0.0, 2.0], [-1.0, 1.0]]; /// let val = integrator.get(2, &my_func, &integration_limit).unwrap(); //double integration /// assert!(f64::abs(val - 16.0) < 1e-7); ///``` - fn get(&self, number_of_integrations: usize, func: &dyn Fn(f64) -> f64, integration_limit: &[[f64; 2]; NUM_INTEGRATIONS]) -> Result - { + fn get( + &self, + number_of_integrations: usize, + func: &dyn Fn(f64) -> f64, + integration_limit: &[[f64; 2]; NUM_INTEGRATIONS], + ) -> Result { self.check_for_errors(number_of_integrations, integration_limit)?; - match self.integration_method - { - GaussianQuadratureMethod::GaussLegendre => return Ok(self.get_gauss_legendre(number_of_integrations, func, integration_limit)), - GaussianQuadratureMethod::GaussHermite => return Ok(self.get_gauss_hermite(number_of_integrations, func, integration_limit)), - GaussianQuadratureMethod::GaussLaguerre => return Ok(self.get_gauss_laguerre(number_of_integrations, func, integration_limit)) + match self.integration_method { + GaussianQuadratureMethod::GaussLegendre => { + return Ok(self.get_gauss_legendre(number_of_integrations, func, integration_limit)) + } + GaussianQuadratureMethod::GaussHermite => { + return Ok(self.get_gauss_hermite(number_of_integrations, func, integration_limit)) + } + GaussianQuadratureMethod::GaussLaguerre => { + return Ok(self.get_gauss_laguerre(number_of_integrations, func, integration_limit)) + } } } } - ///Implements the gaussian quadrature methods for numerical integration for multi variable functions #[derive(Clone, Copy)] -pub struct MultiVariableSolver -{ +pub struct MultiVariableSolver { order: usize, - integration_method: GaussianQuadratureMethod + integration_method: GaussianQuadratureMethod, } -impl Default for MultiVariableSolver -{ +impl Default for MultiVariableSolver { ///default constructor, optimal for most generic polynomial equations - fn default() -> Self - { - return MultiVariableSolver { order: DEFAULT_QUADRATURE_ORDERS, integration_method: GaussianQuadratureMethod::GaussLegendre }; + fn default() -> Self { + return MultiVariableSolver { + order: DEFAULT_QUADRATURE_ORDERS, + integration_method: GaussianQuadratureMethod::GaussLegendre, + }; } } -impl MultiVariableSolver -{ +impl MultiVariableSolver { ///returns the chosen number of nodes/order for quadrature - pub fn get_order(&self) -> usize - { + pub fn get_order(&self) -> usize { return self.order; } ///sets the number of nodes/order for quadrature - pub fn set_order(&mut self, order: usize) - { + pub fn set_order(&mut self, order: usize) { self.order = order; } ///returns the chosen integration method /// possible choices are GaussLegendre, GaussHermite and GaussLaguerre - pub fn get_integration_method(&self) -> GaussianQuadratureMethod - { + pub fn get_integration_method(&self) -> GaussianQuadratureMethod { return self.integration_method; } ///sets the integration method /// possible choices are GaussLegendre, GaussHermite and GaussLaguerre - pub fn set_integration_method(&mut self, integration_method: GaussianQuadratureMethod) - { + pub fn set_integration_method(&mut self, integration_method: GaussianQuadratureMethod) { self.integration_method = integration_method; } ///custom constructor, optimal for fine-tuning for specific cases - pub fn from_parameters(order: usize, integration_method: GaussianQuadratureMethod) -> Self - { - MultiVariableSolver - { + pub fn from_parameters(order: usize, integration_method: GaussianQuadratureMethod) -> Self { + MultiVariableSolver { order, - integration_method - } + integration_method, + } } ///Helper method to check if inputs are well defined - fn check_for_errors(&self, number_of_integrations: usize, integration_limit: &[[f64; 2]; NUM_INTEGRATIONS]) -> Result<(), &'static str> - { + fn check_for_errors( + &self, + number_of_integrations: usize, + integration_limit: &[[f64; 2]; NUM_INTEGRATIONS], + ) -> Result<(), &'static str> { //TODO - if !(1..=gl_table::MAX_GL_ORDER).contains(&self.order) - { + if !(1..=gl_table::MAX_GL_ORDER).contains(&self.order) { return Err(GAUSSIAN_QUADRATURE_ORDER_OUT_OF_RANGE); } - for iter in 0..integration_limit.len() - { - if integration_limit[iter][0] >= integration_limit[iter][1] - { + for iter in 0..integration_limit.len() { + if integration_limit[iter][0] >= integration_limit[iter][1] { return Err(INTEGRATION_LIMITS_ILL_DEFINED); } } - if NUM_INTEGRATIONS != number_of_integrations - { - return Err(INCORRECT_NUMBER_OF_INTEGRATION_LIMITS) - } + if NUM_INTEGRATIONS != number_of_integrations { + return Err(INCORRECT_NUMBER_OF_INTEGRATION_LIMITS); + } - return Ok(()); + return Ok(()); } /// returns the gauss legendre numerical integral for a given equation @@ -323,44 +331,62 @@ impl MultiVariableSolver /// func: the equation to integrate /// integration_limit: the integration bound(s) for each round of integration /// point: for variables not being integrated, it is their constant value, otherwise it is their final upper limit of integration - fn get_gauss_legendre(&self, number_of_integrations: usize, idx_to_integrate: [usize; NUM_INTEGRATIONS], func: &dyn Fn(&[f64; NUM_VARS]) -> f64, integration_limits: &[[f64; 2]; NUM_INTEGRATIONS], point: &[f64; NUM_VARS]) -> f64 - { - if number_of_integrations == 1 - { + fn get_gauss_legendre( + &self, + number_of_integrations: usize, + idx_to_integrate: [usize; NUM_INTEGRATIONS], + func: &dyn Fn(&[f64; NUM_VARS]) -> f64, + integration_limits: &[[f64; 2]; NUM_INTEGRATIONS], + point: &[f64; NUM_VARS], + ) -> f64 { + if number_of_integrations == 1 { let mut ans = 0.0; - let abcsissa_coeff = (integration_limits[0][1] - integration_limits[0][0])/2.0; - let intercept = (integration_limits[0][1] + integration_limits[0][0])/2.0; + let abcsissa_coeff = (integration_limits[0][1] - integration_limits[0][0]) / 2.0; + let intercept = (integration_limits[0][1] + integration_limits[0][0]) / 2.0; let mut args = *point; - for iter in 0..self.order - { - let (abcsissa, weight) = gl_table::get_gl_weights_and_abscissae(self.order, iter).unwrap(); + for iter in 0..self.order { + let (abcsissa, weight) = + gl_table::get_gl_weights_and_abscissae(self.order, iter).unwrap(); - args[idx_to_integrate[0]] = abcsissa_coeff*abcsissa + intercept; + args[idx_to_integrate[0]] = abcsissa_coeff * abcsissa + intercept; - ans = ans + weight*func(&args); + ans = ans + weight * func(&args); } - return abcsissa_coeff*ans; + return abcsissa_coeff * ans; } let mut ans = 0.0; - let abcsissa_coeff = (integration_limits[number_of_integrations-1][1] - integration_limits[number_of_integrations-1][0])/2.0; - let intercept = (integration_limits[number_of_integrations-1][1] + integration_limits[number_of_integrations-1][0])/2.0; + let abcsissa_coeff = (integration_limits[number_of_integrations - 1][1] + - integration_limits[number_of_integrations - 1][0]) + / 2.0; + let intercept = (integration_limits[number_of_integrations - 1][1] + + integration_limits[number_of_integrations - 1][0]) + / 2.0; let mut args = *point; - for iter in 0..self.order - { - let (abcsissa, weight) = gl_table::get_gl_weights_and_abscissae(self.order, iter).unwrap(); - - args[idx_to_integrate[number_of_integrations-1]] = abcsissa_coeff*abcsissa + intercept; - - ans = ans + weight*self.get_gauss_legendre(number_of_integrations-1, idx_to_integrate, func, integration_limits, &args); + for iter in 0..self.order { + let (abcsissa, weight) = + gl_table::get_gl_weights_and_abscissae(self.order, iter).unwrap(); + + args[idx_to_integrate[number_of_integrations - 1]] = + abcsissa_coeff * abcsissa + intercept; + + ans = ans + + weight + * self.get_gauss_legendre( + number_of_integrations - 1, + idx_to_integrate, + func, + integration_limits, + &args, + ); } - return abcsissa_coeff*ans; + return abcsissa_coeff * ans; } /// returns the gauss hermite numerical integral for a given equation @@ -369,21 +395,26 @@ impl MultiVariableSolver /// func: the equation to integrate /// integration_limit: the integration bound(s) for each round of integration /// point: for variables not being integrated, it is their constant value, otherwise it is their final upper limit of integration - fn get_gauss_hermite(&self, number_of_integrations: usize, idx_to_integrate: [usize; NUM_INTEGRATIONS], func: &dyn Fn(&[f64; NUM_VARS]) -> f64, integration_limits: &[[f64; 2]; NUM_INTEGRATIONS], point: &[f64; NUM_VARS]) -> f64 - { - if number_of_integrations == 1 - { + fn get_gauss_hermite( + &self, + number_of_integrations: usize, + idx_to_integrate: [usize; NUM_INTEGRATIONS], + func: &dyn Fn(&[f64; NUM_VARS]) -> f64, + integration_limits: &[[f64; 2]; NUM_INTEGRATIONS], + point: &[f64; NUM_VARS], + ) -> f64 { + if number_of_integrations == 1 { let mut ans = 0.0; let mut args = *point; - for iter in 0..self.order - { - let (abcsissa, weight) = gl_table::get_gl_weights_and_abscissae(self.order, iter).unwrap(); + for iter in 0..self.order { + let (abcsissa, weight) = + gl_table::get_gl_weights_and_abscissae(self.order, iter).unwrap(); args[idx_to_integrate[0]] = abcsissa; - ans = ans + weight*func(&args); + ans = ans + weight * func(&args); } return ans; @@ -393,13 +424,21 @@ impl MultiVariableSolver let mut args = *point; - for iter in 0..self.order - { - let (abcsissa, weight) = gl_table::get_gl_weights_and_abscissae(self.order, iter).unwrap(); - - args[idx_to_integrate[number_of_integrations-1]] = abcsissa; - - ans = ans + weight*self.get_gauss_legendre(number_of_integrations-1, idx_to_integrate, func, integration_limits, &args); + for iter in 0..self.order { + let (abcsissa, weight) = + gl_table::get_gl_weights_and_abscissae(self.order, iter).unwrap(); + + args[idx_to_integrate[number_of_integrations - 1]] = abcsissa; + + ans = ans + + weight + * self.get_gauss_legendre( + number_of_integrations - 1, + idx_to_integrate, + func, + integration_limits, + &args, + ); } return ans; @@ -411,21 +450,26 @@ impl MultiVariableSolver /// func: the equation to integrate /// integration_limit: the integration bound(s) for each round of integration /// point: for variables not being integrated, it is their constant value, otherwise it is their final upper limit of integration - fn get_gauss_laguerre(&self, number_of_integrations: usize, idx_to_integrate: [usize; NUM_INTEGRATIONS], func: &dyn Fn(&[f64; NUM_VARS]) -> f64, integration_limits: &[[f64; 2]; NUM_INTEGRATIONS], point: &[f64; NUM_VARS]) -> f64 - { - if number_of_integrations == 1 - { + fn get_gauss_laguerre( + &self, + number_of_integrations: usize, + idx_to_integrate: [usize; NUM_INTEGRATIONS], + func: &dyn Fn(&[f64; NUM_VARS]) -> f64, + integration_limits: &[[f64; 2]; NUM_INTEGRATIONS], + point: &[f64; NUM_VARS], + ) -> f64 { + if number_of_integrations == 1 { let mut ans = 0.0; let mut args = *point; - for iter in 0..self.order - { - let (abcsissa, weight) = gl_table::get_gl_weights_and_abscissae(self.order, iter).unwrap(); + for iter in 0..self.order { + let (abcsissa, weight) = + gl_table::get_gl_weights_and_abscissae(self.order, iter).unwrap(); args[idx_to_integrate[0]] = abcsissa; - ans = ans + weight*func(&args); + ans = ans + weight * func(&args); } return ans; @@ -435,58 +479,94 @@ impl MultiVariableSolver let mut args = *point; - for iter in 0..self.order - { - let (abcsissa, weight) = gl_table::get_gl_weights_and_abscissae(self.order, iter).unwrap(); - - args[idx_to_integrate[number_of_integrations-1]] = abcsissa; - - ans = ans + weight*self.get_gauss_legendre(number_of_integrations-1, idx_to_integrate, func, integration_limits, &args); + for iter in 0..self.order { + let (abcsissa, weight) = + gl_table::get_gl_weights_and_abscissae(self.order, iter).unwrap(); + + args[idx_to_integrate[number_of_integrations - 1]] = abcsissa; + + ans = ans + + weight + * self.get_gauss_legendre( + number_of_integrations - 1, + idx_to_integrate, + func, + integration_limits, + &args, + ); } return ans; } } -impl IntegratorMultiVariable for MultiVariableSolver -{ +impl IntegratorMultiVariable for MultiVariableSolver { ///returns the gaussian quadrature numerical integration for a single variable equation /// number_of_integrations: number of integrations to perform on the equation /// func: the equation to integrate /// integration_limit: the integration bound(s) for each round of integration - /// + /// /// NOTE: Returns a Result, where possible Err are: /// GAUSSIAN_QUADRATURE_ORDER_OUT_OF_RANGE -> if the chosen numer of nodes/order is out of supported range /// INTEGRATION_LIMITS_ILL_DEFINED -> if any integration_limit[i][0] >= integration_limit[i][1] for all possible i /// INCORRECT_NUMBER_OF_INTEGRATION_LIMITS -> if number_of_integrations is not equal to the size of integration_limit - /// + /// /// assume we want to differentiate f(x,y,z) = 2.0*x + y*z. the function would be: /// ``` - /// let my_func = | args: &[f64; 3] | -> f64 - /// { + /// let my_func = | args: &[f64; 3] | -> f64 + /// { /// return 2.0*args[0] + args[1]*args[2]; /// }; - /// + /// /// use multicalc::numerical_integration::integrator::*; /// use multicalc::numerical_integration::gaussian_integration; - /// + /// /// let integrator = gaussian_integration::MultiVariableSolver::default(); /// let point = [1.0, 2.0, 3.0]; - /// + /// /// let integration_limit = [[0.0, 1.0]; 1]; /// let val = integrator.get(1, [0; 1], &my_func, &integration_limit, &point).unwrap(); //single integration for x /// assert!(f64::abs(val - 7.0) < 1e-7); - /// + /// ///``` - fn get(&self, number_of_integrations: usize, idx_to_integrate: [usize; NUM_INTEGRATIONS], func: &dyn Fn(&[f64; NUM_VARS]) -> f64, integration_limits: &[[f64; 2]; NUM_INTEGRATIONS], point: &[f64; NUM_VARS]) -> Result - { + fn get( + &self, + number_of_integrations: usize, + idx_to_integrate: [usize; NUM_INTEGRATIONS], + func: &dyn Fn(&[f64; NUM_VARS]) -> f64, + integration_limits: &[[f64; 2]; NUM_INTEGRATIONS], + point: &[f64; NUM_VARS], + ) -> Result { self.check_for_errors(number_of_integrations, integration_limits)?; - match self.integration_method - { - GaussianQuadratureMethod::GaussLegendre => return Ok(self.get_gauss_legendre(number_of_integrations, idx_to_integrate, func, integration_limits, point)), - GaussianQuadratureMethod::GaussHermite => return Ok(self.get_gauss_hermite(number_of_integrations, idx_to_integrate, func, integration_limits, point)), - GaussianQuadratureMethod::GaussLaguerre => return Ok(self.get_gauss_laguerre(number_of_integrations, idx_to_integrate, func, integration_limits, point)) + match self.integration_method { + GaussianQuadratureMethod::GaussLegendre => { + return Ok(self.get_gauss_legendre( + number_of_integrations, + idx_to_integrate, + func, + integration_limits, + point, + )) + } + GaussianQuadratureMethod::GaussHermite => { + return Ok(self.get_gauss_hermite( + number_of_integrations, + idx_to_integrate, + func, + integration_limits, + point, + )) + } + GaussianQuadratureMethod::GaussLaguerre => { + return Ok(self.get_gauss_laguerre( + number_of_integrations, + idx_to_integrate, + func, + integration_limits, + point, + )) + } } } -} \ No newline at end of file +} diff --git a/src/numerical_integration/integrator.rs b/src/numerical_integration/integrator.rs index 781fa1a..43b5b7e 100644 --- a/src/numerical_integration/integrator.rs +++ b/src/numerical_integration/integrator.rs @@ -1,34 +1,54 @@ - ///Base trait for single variable numerical integration -pub trait IntegratorSingleVariable: Default + Clone + Copy -{ +pub trait IntegratorSingleVariable: Default + Clone + Copy { ///generic n-th integration of a single variable function - fn get(&self, number_of_integrations: usize, func: &dyn Fn(f64) -> f64, integration_limit: &[[f64; 2]; NUM_INTEGRATIONS]) -> Result; + fn get( + &self, + number_of_integrations: usize, + func: &dyn Fn(f64) -> f64, + integration_limit: &[[f64; 2]; NUM_INTEGRATIONS], + ) -> Result; ///convenience wrapper for a single integral of a single variable function - fn get_single(&self, func: &dyn Fn(f64) -> f64, integration_limit: &[f64; 2]) -> Result - { + fn get_single( + &self, + func: &dyn Fn(f64) -> f64, + integration_limit: &[f64; 2], + ) -> Result { let new_limits: [[f64; 2]; 1] = [*integration_limit]; return self.get(1, func, &new_limits); } ///convenience wrapper for a double integral of a single variable function - fn get_double(&self, func: &dyn Fn(f64) -> f64, integration_limit: &[[f64; 2]; 2]) -> Result - { + fn get_double( + &self, + func: &dyn Fn(f64) -> f64, + integration_limit: &[[f64; 2]; 2], + ) -> Result { return self.get(2, func, integration_limit); } } ///Base trait for multi-variable numerical integration -pub trait IntegratorMultiVariable : Default + Clone + Copy -{ +pub trait IntegratorMultiVariable: Default + Clone + Copy { ///generic n-th partial integration of a multi variable function - fn get(&self, number_of_integrations: usize, idx_to_integrate: [usize; NUM_INTEGRATIONS], func: &dyn Fn(&[f64; NUM_VARS]) -> f64, integration_limits: &[[f64; 2]; NUM_INTEGRATIONS], point: &[f64; NUM_VARS]) -> Result; + fn get( + &self, + number_of_integrations: usize, + idx_to_integrate: [usize; NUM_INTEGRATIONS], + func: &dyn Fn(&[f64; NUM_VARS]) -> f64, + integration_limits: &[[f64; 2]; NUM_INTEGRATIONS], + point: &[f64; NUM_VARS], + ) -> Result; ///convenience wrapper for a single partial integral of a multi variable function - fn get_single_partial(&self, func: &dyn Fn(&[f64; NUM_VARS]) -> f64, idx_to_integrate: usize, integration_limits: &[f64; 2], point: &[f64; NUM_VARS]) -> Result - { + fn get_single_partial( + &self, + func: &dyn Fn(&[f64; NUM_VARS]) -> f64, + idx_to_integrate: usize, + integration_limits: &[f64; 2], + point: &[f64; NUM_VARS], + ) -> Result { let new_limits: [[f64; 2]; 1] = [*integration_limits]; let new_idx: [usize; 1] = [idx_to_integrate]; @@ -36,8 +56,13 @@ pub trait IntegratorMultiVariable : Default + Clone + Copy } ///convenience wrapper for a double partial integral of a multi variable function - fn get_double_partial(&self, func: &dyn Fn(&[f64; NUM_VARS]) -> f64, idx_to_integrate: [usize; 2], integration_limits: &[[f64; 2]; 2], point: &[f64; NUM_VARS]) -> Result - { + fn get_double_partial( + &self, + func: &dyn Fn(&[f64; NUM_VARS]) -> f64, + idx_to_integrate: [usize; 2], + integration_limits: &[[f64; 2]; 2], + point: &[f64; NUM_VARS], + ) -> Result { return self.get(2, idx_to_integrate, func, integration_limits, point); } -} \ No newline at end of file +} diff --git a/src/numerical_integration/iterative_integration.rs b/src/numerical_integration/iterative_integration.rs index 3460908..78c244a 100644 --- a/src/numerical_integration/iterative_integration.rs +++ b/src/numerical_integration/iterative_integration.rs @@ -1,4 +1,3 @@ - use crate::numerical_integration::integrator::*; use crate::numerical_integration::mode::IterativeMethod; use crate::utils::error_codes::*; @@ -7,184 +6,170 @@ pub const DEFAULT_TOTAL_ITERATIONS: u64 = 100; ///Implements the iterative methods for numerical integration for single variable functions #[derive(Clone, Copy)] -pub struct SingleVariableSolver -{ +pub struct SingleVariableSolver { total_iterations: u64, - integration_method: IterativeMethod + integration_method: IterativeMethod, } -impl Default for SingleVariableSolver -{ +impl Default for SingleVariableSolver { ///default constructor, optimal for most generic equations - fn default() -> Self - { - return SingleVariableSolver { total_iterations: DEFAULT_TOTAL_ITERATIONS, integration_method: IterativeMethod::Booles }; + fn default() -> Self { + return SingleVariableSolver { + total_iterations: DEFAULT_TOTAL_ITERATIONS, + integration_method: IterativeMethod::Booles, + }; } } -impl SingleVariableSolver -{ +impl SingleVariableSolver { ///returns the total nuber of iterations - pub fn get_total_iterations(&self) -> u64 - { + pub fn get_total_iterations(&self) -> u64 { return self.total_iterations; } ///sets the total nuber of iterations - pub fn set_total_iterations(&mut self, total_iterations: u64) - { + pub fn set_total_iterations(&mut self, total_iterations: u64) { self.total_iterations = total_iterations; } ///returns the chosen integration method /// choices are: Booles, Simpsons and Trapezoidal - pub fn get_integration_method(&self) -> IterativeMethod - { + pub fn get_integration_method(&self) -> IterativeMethod { return self.integration_method; } ///sets the integration method ///choices are: Booles, Simpsons and Trapezoidal - pub fn set_integration_method(&mut self, integration_method: IterativeMethod) - { + pub fn set_integration_method(&mut self, integration_method: IterativeMethod) { self.integration_method = integration_method; } ///custom constructor. Optimal for fine-tuning for more complex equations - pub fn from_parameters(total_iterations: u64, integration_method: IterativeMethod) -> Self - { - SingleVariableSolver - { + pub fn from_parameters(total_iterations: u64, integration_method: IterativeMethod) -> Self { + SingleVariableSolver { total_iterations: total_iterations, - integration_method: integration_method - } + integration_method: integration_method, + } } ///Helper method to check if inputs are well defined - fn check_for_errors(&self, number_of_integrations: usize, integration_limit: &[[f64; 2]; NUM_INTEGRATIONS]) -> Result<(), &'static str> - { - if self.total_iterations == 0 - { + fn check_for_errors( + &self, + number_of_integrations: usize, + integration_limit: &[[f64; 2]; NUM_INTEGRATIONS], + ) -> Result<(), &'static str> { + if self.total_iterations == 0 { return Err(INTEGRATION_CANNOT_HAVE_ZERO_ITERATIONS); } - for iter in 0..integration_limit.len() - { - if integration_limit[iter][0] >= integration_limit[iter][1] - { + for iter in 0..integration_limit.len() { + if integration_limit[iter][0] >= integration_limit[iter][1] { return Err(INTEGRATION_LIMITS_ILL_DEFINED); } } - if NUM_INTEGRATIONS != number_of_integrations - { - return Err(INCORRECT_NUMBER_OF_INTEGRATION_LIMITS) - } + if NUM_INTEGRATIONS != number_of_integrations { + return Err(INCORRECT_NUMBER_OF_INTEGRATION_LIMITS); + } - return Ok(()); + return Ok(()); } ///returns the numerical integration via Booles' method ///number_of_integrations: number of times the equation needs to be integrated /// func: The function to integrate /// integration_limit: the integration bound(s) for each round of integration - fn get_booles(&self, number_of_integrations: usize, func: &dyn Fn(f64) -> f64, integration_limit: &[[f64; 2]; NUM_INTEGRATIONS]) -> f64 - { - if number_of_integrations == 1 - { + fn get_booles( + &self, + number_of_integrations: usize, + func: &dyn Fn(f64) -> f64, + integration_limit: &[[f64; 2]; NUM_INTEGRATIONS], + ) -> f64 { + if number_of_integrations == 1 { let mut current_point = integration_limit[0][0]; - let mut ans = 7.0*func(current_point); - let delta = (integration_limit[0][1] - integration_limit[0][0])/(self.total_iterations as f64); + let mut ans = 7.0 * func(current_point); + let delta = (integration_limit[0][1] - integration_limit[0][0]) + / (self.total_iterations as f64); let mut multiplier = 32.0; - for iter in 0..self.total_iterations-1 - { + for iter in 0..self.total_iterations - 1 { current_point = current_point + delta; - ans = ans + multiplier*func(current_point); - - if (iter + 2) % 2 != 0 - { + ans = ans + multiplier * func(current_point); + + if (iter + 2) % 2 != 0 { multiplier = 32.0; - } - else if (iter + 2) % 4 == 0 - { + } else if (iter + 2) % 4 == 0 { multiplier = 14.0; - } - else - { + } else { multiplier = 12.0; } } current_point = integration_limit[0][1]; - ans = ans + 7.0*func(current_point); + ans = ans + 7.0 * func(current_point); - return 2.0*delta*ans/45.0; + return 2.0 * delta * ans / 45.0; } let mut current_point = integration_limit[number_of_integrations - 1][0]; - let mut ans = 7.0*self.get_booles(number_of_integrations - 1, func, integration_limit); - let delta = (integration_limit[number_of_integrations - 1][1] - integration_limit[number_of_integrations - 1][0])/(self.total_iterations as f64); + let mut ans = 7.0 * self.get_booles(number_of_integrations - 1, func, integration_limit); + let delta = (integration_limit[number_of_integrations - 1][1] + - integration_limit[number_of_integrations - 1][0]) + / (self.total_iterations as f64); let mut multiplier = 32.0; - for iter in 0..self.total_iterations-1 - { + for iter in 0..self.total_iterations - 1 { current_point = current_point + delta; - ans = ans + multiplier*self.get_booles(number_of_integrations - 1, func, integration_limit); - - if (iter + 2) % 2 != 0 - { + ans = ans + + multiplier * self.get_booles(number_of_integrations - 1, func, integration_limit); + + if (iter + 2) % 2 != 0 { multiplier = 32.0; - } - else if (iter + 2) % 4 == 0 - { + } else if (iter + 2) % 4 == 0 { multiplier = 14.0; - } - else - { + } else { multiplier = 12.0 } } //current_point = integration_limit[1]; - ans = ans + 7.0*self.get_booles(number_of_integrations - 1, func, integration_limit); + ans = ans + 7.0 * self.get_booles(number_of_integrations - 1, func, integration_limit); - return 2.0*delta*ans/45.0; + return 2.0 * delta * ans / 45.0; } - ///returns the numerical integration via Simsons 3/8th method ///number_of_integrations: number of times the equation needs to be integrated /// func: The function to integrate /// integration_limit: the integration bound(s) for each round of integration - fn get_simpsons(&self, number_of_integrations: usize, func: &dyn Fn(f64) -> f64, integration_limit: &[[f64; 2]; NUM_INTEGRATIONS]) -> f64 - { - if number_of_integrations == 1 - { + fn get_simpsons( + &self, + number_of_integrations: usize, + func: &dyn Fn(f64) -> f64, + integration_limit: &[[f64; 2]; NUM_INTEGRATIONS], + ) -> f64 { + if number_of_integrations == 1 { let mut current_point = integration_limit[0][0]; let mut ans = func(current_point); - let delta = (integration_limit[0][1] - integration_limit[0][0])/(self.total_iterations as f64); + let delta = (integration_limit[0][1] - integration_limit[0][0]) + / (self.total_iterations as f64); let mut multiplier = 3.0; - for iter in 0..self.total_iterations-1 - { + for iter in 0..self.total_iterations - 1 { current_point = current_point + delta; - ans = ans + multiplier*func(current_point); + ans = ans + multiplier * func(current_point); - if (iter + 2) % 3 == 0 - { + if (iter + 2) % 3 == 0 { multiplier = 2.0; - } - else - { + } else { multiplier = 3.0; } } @@ -193,27 +178,27 @@ impl SingleVariableSolver ans = ans + func(current_point); - return 3.0*delta*ans/8.0; + return 3.0 * delta * ans / 8.0; } let mut current_point = integration_limit[number_of_integrations - 1][0]; let mut ans = self.get_simpsons(number_of_integrations - 1, func, integration_limit); - let delta = (integration_limit[number_of_integrations - 1][1] - integration_limit[number_of_integrations - 1][0])/(self.total_iterations as f64); + let delta = (integration_limit[number_of_integrations - 1][1] + - integration_limit[number_of_integrations - 1][0]) + / (self.total_iterations as f64); let mut multiplier = 3.0; - for iter in 0..self.total_iterations-1 - { + for iter in 0..self.total_iterations - 1 { current_point = current_point + delta; - ans = ans + multiplier*self.get_simpsons(number_of_integrations - 1, func, integration_limit); + ans = ans + + multiplier + * self.get_simpsons(number_of_integrations - 1, func, integration_limit); - if (iter + 2) % 3 == 0 - { + if (iter + 2) % 3 == 0 { multiplier = 2.0; - } - else - { + } else { multiplier = 3.0; } } @@ -222,83 +207,87 @@ impl SingleVariableSolver ans = ans + self.get_simpsons(number_of_integrations - 1, func, integration_limit); - return 3.0*delta*ans/8.0; + return 3.0 * delta * ans / 8.0; } ///returns the numerical integration via Trapezoidal method ///number_of_integrations: number of times the equation needs to be integrated /// func: The function to integrate /// integration_limit: the integration bound(s) for each round of integration - fn get_trapezoidal(&self, number_of_integrations: usize, func: &dyn Fn(f64) -> f64, integration_limit: &[[f64; 2]; NUM_INTEGRATIONS]) -> f64 - { - if number_of_integrations == 1 - { + fn get_trapezoidal( + &self, + number_of_integrations: usize, + func: &dyn Fn(f64) -> f64, + integration_limit: &[[f64; 2]; NUM_INTEGRATIONS], + ) -> f64 { + if number_of_integrations == 1 { let mut current_point = integration_limit[0][0]; let mut ans = func(current_point); - let delta = (integration_limit[0][1] - integration_limit[0][0])/(self.total_iterations as f64); + let delta = (integration_limit[0][1] - integration_limit[0][0]) + / (self.total_iterations as f64); - for _ in 0..self.total_iterations-1 - { + for _ in 0..self.total_iterations - 1 { current_point = current_point + delta; - ans = ans + 2.0*func(current_point); + ans = ans + 2.0 * func(current_point); } - + current_point = integration_limit[0][1]; ans = ans + func(current_point); - return 0.5*delta*ans; + return 0.5 * delta * ans; } let mut current_point = integration_limit[number_of_integrations - 1][0]; let mut ans = self.get_trapezoidal(number_of_integrations - 1, func, integration_limit); - let delta = (integration_limit[number_of_integrations - 1][1] - integration_limit[number_of_integrations - 1][0])/(self.total_iterations as f64); + let delta = (integration_limit[number_of_integrations - 1][1] + - integration_limit[number_of_integrations - 1][0]) + / (self.total_iterations as f64); - for _ in 0..self.total_iterations-1 - { + for _ in 0..self.total_iterations - 1 { current_point = current_point + delta; - ans = ans + 2.0*self.get_trapezoidal(number_of_integrations - 1, func, integration_limit); + ans = ans + + 2.0 * self.get_trapezoidal(number_of_integrations - 1, func, integration_limit); } - + //current_point = integration_limit[1]; ans = ans + self.get_trapezoidal(number_of_integrations - 1, func, integration_limit); - return 0.5*delta*ans; + return 0.5 * delta * ans; } } -impl IntegratorSingleVariable for SingleVariableSolver -{ +impl IntegratorSingleVariable for SingleVariableSolver { ///returns the numeric integration value for a single variable function ///number_of_integrations: number of times the equation needs to be integrated /// func: The function to integrate /// integration_limit: the integration bound(s) for each round of integration - /// + /// /// NOTE: Returns a Result, /// where possible Err are: /// INTEGRATION_CANNOT_HAVE_ZERO_ITERATIONS -> if number_of_integrations is zero /// INTEGRATION_LIMITS_ILL_DEFINED -> if any integration_limit[i][0] >= integration_limit[i][1] for all possible i /// INCORRECT_NUMBER_OF_INTEGRATION_LIMITS -> if size of integration_limit is not equal to number_of_integrations - /// + /// /// assume we want to integrate 2*x . the function would be: /// ``` - /// let my_func = | arg: f64 | -> f64 - /// { + /// let my_func = | arg: f64 | -> f64 + /// { /// return 2.0*arg; /// }; - /// + /// /// use crate::multicalc::numerical_integration::integrator::*; /// use multicalc::numerical_integration::iterative_integration; /// /// let integrator = iterative_integration::SingleVariableSolver::default(); - /// - /// let integration_limit = [[0.0, 2.0]; 1]; //desired integration limit + /// + /// let integration_limit = [[0.0, 2.0]; 1]; //desired integration limit /// let val = integrator.get(1, &my_func, &integration_limit).unwrap(); //single integration /// assert!(f64::abs(val - 4.0) < 1e-6); - /// + /// /// let integration_limit = [[0.0, 2.0], [-1.0, 1.0]]; //desired integration limits /// let val = integrator.get(2, &my_func, &integration_limit).unwrap(); //double integration /// assert!(f64::abs(val - 8.0) < 1e-6); @@ -307,176 +296,197 @@ impl IntegratorSingleVariable for SingleVariableSolver /// let val = integrator.get(3, &my_func, &integration_limit).unwrap(); //triple integration /// assert!(f64::abs(val - 16.0) < 1e-6); ///``` - fn get(&self, number_of_integrations: usize, func: &dyn Fn(f64) -> f64, integration_limit: &[[f64; 2]; NUM_INTEGRATIONS]) -> Result - { + fn get( + &self, + number_of_integrations: usize, + func: &dyn Fn(f64) -> f64, + integration_limit: &[[f64; 2]; NUM_INTEGRATIONS], + ) -> Result { self.check_for_errors(number_of_integrations, integration_limit)?; - match self.integration_method - { - IterativeMethod::Booles => return Ok(self.get_booles(number_of_integrations, func, integration_limit)), - IterativeMethod::Simpsons => return Ok(self.get_simpsons(number_of_integrations, func, integration_limit)), - IterativeMethod::Trapezoidal => return Ok(self.get_trapezoidal(number_of_integrations, func, integration_limit)) - } + match self.integration_method { + IterativeMethod::Booles => { + return Ok(self.get_booles(number_of_integrations, func, integration_limit)) + } + IterativeMethod::Simpsons => { + return Ok(self.get_simpsons(number_of_integrations, func, integration_limit)) + } + IterativeMethod::Trapezoidal => { + return Ok(self.get_trapezoidal(number_of_integrations, func, integration_limit)) + } + } } } - ///Implements the iterative methods for numerical integration for multi variable functions #[derive(Clone, Copy)] -pub struct MultiVariableSolver -{ +pub struct MultiVariableSolver { total_iterations: u64, - integration_method: IterativeMethod + integration_method: IterativeMethod, } -impl Default for MultiVariableSolver -{ +impl Default for MultiVariableSolver { ///default constructor, optimal for most generic equations - fn default() -> Self - { - return MultiVariableSolver { total_iterations: DEFAULT_TOTAL_ITERATIONS, integration_method: IterativeMethod::Booles }; + fn default() -> Self { + return MultiVariableSolver { + total_iterations: DEFAULT_TOTAL_ITERATIONS, + integration_method: IterativeMethod::Booles, + }; } } -impl MultiVariableSolver -{ +impl MultiVariableSolver { ///returns the total number of iterations - pub fn get_total_iterations(&self) -> u64 - { + pub fn get_total_iterations(&self) -> u64 { return self.total_iterations; } ///sets the total number of iterations - pub fn set_total_iterations(&mut self, total_iterations: u64) - { + pub fn set_total_iterations(&mut self, total_iterations: u64) { self.total_iterations = total_iterations; } ///returns the chosen integration method /// choices are: Booles, Simpsons and Trapezoidal - pub fn get_integration_method(&self) -> IterativeMethod - { + pub fn get_integration_method(&self) -> IterativeMethod { return self.integration_method; } ///sets the integration method /// choices are: Booles, Simpsons and Trapezoidal - pub fn set_integration_method(&mut self, integration_method: IterativeMethod) - { + pub fn set_integration_method(&mut self, integration_method: IterativeMethod) { self.integration_method = integration_method; } ///custom constructor, optimal for fine-tuning the integrator for more complex equations - pub fn from_parameters(total_iterations: u64, integration_method: IterativeMethod) -> Self - { - MultiVariableSolver - { + pub fn from_parameters(total_iterations: u64, integration_method: IterativeMethod) -> Self { + MultiVariableSolver { total_iterations: total_iterations, - integration_method: integration_method - } + integration_method: integration_method, + } } ///Helper method to check if inputs are well defined - fn check_for_errors(&self, number_of_integrations: usize, integration_limit: &[[f64; 2]; NUM_INTEGRATIONS]) -> Result<(), &'static str> - { - if self.total_iterations == 0 - { + fn check_for_errors( + &self, + number_of_integrations: usize, + integration_limit: &[[f64; 2]; NUM_INTEGRATIONS], + ) -> Result<(), &'static str> { + if self.total_iterations == 0 { return Err(INTEGRATION_CANNOT_HAVE_ZERO_ITERATIONS); } - for iter in 0..integration_limit.len() - { - if integration_limit[iter][0] >= integration_limit[iter][1] - { + for iter in 0..integration_limit.len() { + if integration_limit[iter][0] >= integration_limit[iter][1] { return Err(INTEGRATION_LIMITS_ILL_DEFINED); } } - if NUM_INTEGRATIONS != number_of_integrations - { - return Err(INCORRECT_NUMBER_OF_INTEGRATION_LIMITS) - } + if NUM_INTEGRATIONS != number_of_integrations { + return Err(INCORRECT_NUMBER_OF_INTEGRATION_LIMITS); + } - return Ok(()); + return Ok(()); } - ///returns the numerical integration via Booles' method ///number_of_integrations: number of times the equation needs to be integrated /// idx_to_integrate: the variables' index/indices that needs to be integrated /// func: The function to integrate /// integration_limit: the integration bound(s) for each round of integration /// point: for variables not being integrated, it is their constant value, otherwise it is their final upper limit of integration - fn get_booles(&self, number_of_integrations: usize, idx_to_integrate: [usize; NUM_INTEGRATIONS], func: &dyn Fn(&[f64; NUM_VARS]) -> f64, integration_limits: &[[f64; 2]; NUM_INTEGRATIONS], point: &[f64; NUM_VARS]) -> f64 - { - if number_of_integrations == 1 - { + fn get_booles( + &self, + number_of_integrations: usize, + idx_to_integrate: [usize; NUM_INTEGRATIONS], + func: &dyn Fn(&[f64; NUM_VARS]) -> f64, + integration_limits: &[[f64; 2]; NUM_INTEGRATIONS], + point: &[f64; NUM_VARS], + ) -> f64 { + if number_of_integrations == 1 { let mut current_vec = *point; current_vec[idx_to_integrate[0]] = integration_limits[0][0]; - let mut ans = 7.0*func(¤t_vec); - let delta = (integration_limits[0][1] - integration_limits[0][0])/(self.total_iterations as f64); + let mut ans = 7.0 * func(¤t_vec); + let delta = (integration_limits[0][1] - integration_limits[0][0]) + / (self.total_iterations as f64); let mut multiplier = 32.0; - for iter in 0..self.total_iterations-1 - { + for iter in 0..self.total_iterations - 1 { current_vec[idx_to_integrate[0]] = current_vec[idx_to_integrate[0]] + delta; - ans = ans + multiplier*func(¤t_vec); - - if (iter + 2) % 2 != 0 - { + ans = ans + multiplier * func(¤t_vec); + + if (iter + 2) % 2 != 0 { multiplier = 32.0; - } - else if (iter + 2) % 4 == 0 - { + } else if (iter + 2) % 4 == 0 { multiplier = 14.0; - } - else - { + } else { multiplier = 12.0; } } current_vec[idx_to_integrate[0]] = integration_limits[0][1]; - ans = ans + 7.0*func(¤t_vec); + ans = ans + 7.0 * func(¤t_vec); - return 2.0*delta*ans/45.0; + return 2.0 * delta * ans / 45.0; } let mut current_vec = *point; - current_vec[idx_to_integrate[number_of_integrations - 1]] = integration_limits[number_of_integrations - 1][0]; - - let mut ans = 7.0*self.get_booles(number_of_integrations-1, idx_to_integrate, func, integration_limits, ¤t_vec); - let delta = (integration_limits[number_of_integrations - 1][1] - integration_limits[number_of_integrations - 1][0])/(self.total_iterations as f64); + current_vec[idx_to_integrate[number_of_integrations - 1]] = + integration_limits[number_of_integrations - 1][0]; + + let mut ans = 7.0 + * self.get_booles( + number_of_integrations - 1, + idx_to_integrate, + func, + integration_limits, + ¤t_vec, + ); + let delta = (integration_limits[number_of_integrations - 1][1] + - integration_limits[number_of_integrations - 1][0]) + / (self.total_iterations as f64); let mut multiplier = 32.0; - for iter in 0..self.total_iterations-1 - { - current_vec[idx_to_integrate[number_of_integrations - 1]] = current_vec[idx_to_integrate[number_of_integrations - 1]] + delta; - ans = ans + multiplier*self.get_booles(number_of_integrations-1, idx_to_integrate, func, integration_limits, ¤t_vec); - - if (iter + 2) % 2 != 0 - { + for iter in 0..self.total_iterations - 1 { + current_vec[idx_to_integrate[number_of_integrations - 1]] = + current_vec[idx_to_integrate[number_of_integrations - 1]] + delta; + ans = ans + + multiplier + * self.get_booles( + number_of_integrations - 1, + idx_to_integrate, + func, + integration_limits, + ¤t_vec, + ); + + if (iter + 2) % 2 != 0 { multiplier = 32.0; - } - else if (iter + 2) % 4 == 0 - { + } else if (iter + 2) % 4 == 0 { multiplier = 14.0; - } - else - { + } else { multiplier = 12.0; } } - current_vec[idx_to_integrate[number_of_integrations - 1]] = integration_limits[number_of_integrations - 1][1]; + current_vec[idx_to_integrate[number_of_integrations - 1]] = + integration_limits[number_of_integrations - 1][1]; - ans = ans + 7.0*self.get_booles(number_of_integrations-1, idx_to_integrate, func, integration_limits, ¤t_vec); + ans = ans + + 7.0 + * self.get_booles( + number_of_integrations - 1, + idx_to_integrate, + func, + integration_limits, + ¤t_vec, + ); - return 2.0*delta*ans/45.0; + return 2.0 * delta * ans / 45.0; } ///returns the numerical integration via Simsons' 3/8th method @@ -485,29 +495,31 @@ impl MultiVariableSolver /// func: The function to integrate /// integration_limit: the integration bound(s) for each round of integration /// point: for variables not being integrated, it is their constant value, otherwise it is their final upper limit of integration - fn get_simpsons(&self, number_of_integrations: usize, idx_to_integrate: [usize; NUM_INTEGRATIONS], func: &dyn Fn(&[f64; NUM_VARS]) -> f64, integration_limits: &[[f64; 2]; NUM_INTEGRATIONS], point: &[f64; NUM_VARS]) -> f64 - { - if number_of_integrations == 1 - { + fn get_simpsons( + &self, + number_of_integrations: usize, + idx_to_integrate: [usize; NUM_INTEGRATIONS], + func: &dyn Fn(&[f64; NUM_VARS]) -> f64, + integration_limits: &[[f64; 2]; NUM_INTEGRATIONS], + point: &[f64; NUM_VARS], + ) -> f64 { + if number_of_integrations == 1 { let mut current_vec = *point; current_vec[idx_to_integrate[0]] = integration_limits[0][0]; let mut ans = func(¤t_vec); - let delta = (integration_limits[0][1] - integration_limits[0][0])/(self.total_iterations as f64); + let delta = (integration_limits[0][1] - integration_limits[0][0]) + / (self.total_iterations as f64); let mut multiplier = 3.0; - for iter in 0..self.total_iterations-1 - { + for iter in 0..self.total_iterations - 1 { current_vec[idx_to_integrate[0]] = current_vec[idx_to_integrate[0]] + delta; - ans = ans + multiplier*func(¤t_vec); + ans = ans + multiplier * func(¤t_vec); - if (iter + 2) % 3 == 0 - { + if (iter + 2) % 3 == 0 { multiplier = 2.0; - } - else - { + } else { multiplier = 3.0; } } @@ -516,37 +528,59 @@ impl MultiVariableSolver ans = ans + func(¤t_vec); - return 3.0*delta*ans/8.0; + return 3.0 * delta * ans / 8.0; } let mut current_vec = *point; - current_vec[idx_to_integrate[number_of_integrations - 1]] = integration_limits[number_of_integrations - 1][0]; - - let mut ans = self.get_simpsons(number_of_integrations-1, idx_to_integrate, func, integration_limits, ¤t_vec); - let delta = (integration_limits[number_of_integrations - 1][1] - integration_limits[number_of_integrations - 1][0])/(self.total_iterations as f64); + current_vec[idx_to_integrate[number_of_integrations - 1]] = + integration_limits[number_of_integrations - 1][0]; + + let mut ans = self.get_simpsons( + number_of_integrations - 1, + idx_to_integrate, + func, + integration_limits, + ¤t_vec, + ); + let delta = (integration_limits[number_of_integrations - 1][1] + - integration_limits[number_of_integrations - 1][0]) + / (self.total_iterations as f64); let mut multiplier = 3.0; - for iter in 0..self.total_iterations-1 - { - current_vec[idx_to_integrate[number_of_integrations - 1]] = current_vec[idx_to_integrate[number_of_integrations - 1]] + delta; - ans = ans + multiplier*self.get_simpsons(number_of_integrations-1, idx_to_integrate, func, integration_limits, ¤t_vec); - - if (iter + 2) % 3 == 0 - { + for iter in 0..self.total_iterations - 1 { + current_vec[idx_to_integrate[number_of_integrations - 1]] = + current_vec[idx_to_integrate[number_of_integrations - 1]] + delta; + ans = ans + + multiplier + * self.get_simpsons( + number_of_integrations - 1, + idx_to_integrate, + func, + integration_limits, + ¤t_vec, + ); + + if (iter + 2) % 3 == 0 { multiplier = 2.0; - } - else - { + } else { multiplier = 3.0; } } - current_vec[idx_to_integrate[number_of_integrations - 1]] = integration_limits[number_of_integrations - 1][1]; + current_vec[idx_to_integrate[number_of_integrations - 1]] = + integration_limits[number_of_integrations - 1][1]; - ans = ans + self.get_simpsons(number_of_integrations-1, idx_to_integrate, func, integration_limits, ¤t_vec); + ans = ans + + self.get_simpsons( + number_of_integrations - 1, + idx_to_integrate, + func, + integration_limits, + ¤t_vec, + ); - return 3.0*delta*ans/8.0; + return 3.0 * delta * ans / 8.0; } ///returns the numerical integration via Trapezoidal method @@ -555,51 +589,80 @@ impl MultiVariableSolver /// func: The function to integrate /// integration_limit: the integration bound(s) for each round of integration /// point: for variables not being integrated, it is their constant value, otherwise it is their final upper limit of integration - fn get_trapezoidal(&self, number_of_integrations: usize, idx_to_integrate: [usize; NUM_INTEGRATIONS], func: &dyn Fn(&[f64; NUM_VARS]) -> f64, integration_limits: &[[f64; 2]; NUM_INTEGRATIONS], point: &[f64; NUM_VARS]) -> f64 - { - if number_of_integrations == 1 - { + fn get_trapezoidal( + &self, + number_of_integrations: usize, + idx_to_integrate: [usize; NUM_INTEGRATIONS], + func: &dyn Fn(&[f64; NUM_VARS]) -> f64, + integration_limits: &[[f64; 2]; NUM_INTEGRATIONS], + point: &[f64; NUM_VARS], + ) -> f64 { + if number_of_integrations == 1 { let mut current_vec = *point; current_vec[idx_to_integrate[0]] = integration_limits[0][0]; let mut ans = func(¤t_vec); - let delta = (integration_limits[0][1] - integration_limits[0][0])/(self.total_iterations as f64); + let delta = (integration_limits[0][1] - integration_limits[0][0]) + / (self.total_iterations as f64); - for _ in 0..self.total_iterations-1 - { + for _ in 0..self.total_iterations - 1 { current_vec[idx_to_integrate[0]] = current_vec[idx_to_integrate[0]] + delta; - ans = ans + 2.0*func(¤t_vec); + ans = ans + 2.0 * func(¤t_vec); } - + current_vec[idx_to_integrate[0]] = integration_limits[0][1]; ans = ans + func(¤t_vec); - return 0.5*delta*ans; + return 0.5 * delta * ans; } let mut current_vec = *point; - current_vec[idx_to_integrate[number_of_integrations - 1]] = integration_limits[number_of_integrations - 1][0]; - - let mut ans = self.get_trapezoidal(number_of_integrations-1, idx_to_integrate, func, integration_limits, ¤t_vec); - let delta = (integration_limits[number_of_integrations - 1][1] - integration_limits[number_of_integrations - 1][0])/(self.total_iterations as f64); - - for _ in 0..self.total_iterations-1 - { - current_vec[idx_to_integrate[number_of_integrations - 1]] = current_vec[idx_to_integrate[number_of_integrations - 1]] + delta; - ans = ans + 2.0*self.get_trapezoidal(number_of_integrations-1, idx_to_integrate, func, integration_limits, ¤t_vec); + current_vec[idx_to_integrate[number_of_integrations - 1]] = + integration_limits[number_of_integrations - 1][0]; + + let mut ans = self.get_trapezoidal( + number_of_integrations - 1, + idx_to_integrate, + func, + integration_limits, + ¤t_vec, + ); + let delta = (integration_limits[number_of_integrations - 1][1] + - integration_limits[number_of_integrations - 1][0]) + / (self.total_iterations as f64); + + for _ in 0..self.total_iterations - 1 { + current_vec[idx_to_integrate[number_of_integrations - 1]] = + current_vec[idx_to_integrate[number_of_integrations - 1]] + delta; + ans = ans + + 2.0 + * self.get_trapezoidal( + number_of_integrations - 1, + idx_to_integrate, + func, + integration_limits, + ¤t_vec, + ); } - - current_vec[idx_to_integrate[number_of_integrations - 1]] = integration_limits[number_of_integrations - 1][1]; - ans = ans + self.get_trapezoidal(number_of_integrations-1, idx_to_integrate, func, integration_limits, ¤t_vec); + current_vec[idx_to_integrate[number_of_integrations - 1]] = + integration_limits[number_of_integrations - 1][1]; + + ans = ans + + self.get_trapezoidal( + number_of_integrations - 1, + idx_to_integrate, + func, + integration_limits, + ¤t_vec, + ); - return 0.5*delta*ans; + return 0.5 * delta * ans; } } -impl IntegratorMultiVariable for MultiVariableSolver -{ +impl IntegratorMultiVariable for MultiVariableSolver { ///returns the numeric integration value for a multi-variable function /// number_of_integrations: number of times the equation needs to be integrated /// func: The function to integrate @@ -607,39 +670,68 @@ impl IntegratorMultiVariable for MultiVariableSolver /// func: The function to integrate /// integration_limit: the integration bound(s) for each round of integration /// point: for variables not being integrated, it is their constant value, otherwise it is their final upper limit of integration - /// + /// /// NOTE: Returns a Result, /// where possible Err are: /// INTEGRATION_CANNOT_HAVE_ZERO_ITERATIONS -> if number_of_integrations is zero /// INTEGRATION_LIMITS_ILL_DEFINED -> if any integration_limit[i][0] >= integration_limit[i][1] for all possible i /// INCORRECT_NUMBER_OF_INTEGRATION_LIMITS -> if size of integration_limit is not equal to number_of_integrations - /// + /// /// assume we want to integrate 2.0*x + y*z . the function would be: /// ``` - /// let func = | args: &[f64; 3] | -> f64 - ///{ + /// let func = | args: &[f64; 3] | -> f64 + ///{ /// return 2.0*args[0] + args[1]*args[2]; ///}; /// let point = [1.0, 2.0, 3.0]; - /// + /// /// use crate::multicalc::numerical_integration::integrator::*; /// use multicalc::numerical_integration::iterative_integration; - /// + /// /// let integrator = iterative_integration::MultiVariableSolver::default(); - /// + /// /// let integration_limit = [[0.0, 1.0]; 1]; //desired integation limit /// let val = integrator.get(1, [0; 1], &func, &integration_limit, &point).unwrap(); /// assert!(f64::abs(val - 7.0) < 1e-6); /// ``` - fn get(&self, number_of_integrations: usize, idx_to_integrate: [usize; NUM_INTEGRATIONS], func: &dyn Fn(&[f64; NUM_VARS]) -> f64, integration_limits: &[[f64; 2]; NUM_INTEGRATIONS], point: &[f64; NUM_VARS]) -> Result - { + fn get( + &self, + number_of_integrations: usize, + idx_to_integrate: [usize; NUM_INTEGRATIONS], + func: &dyn Fn(&[f64; NUM_VARS]) -> f64, + integration_limits: &[[f64; 2]; NUM_INTEGRATIONS], + point: &[f64; NUM_VARS], + ) -> Result { self.check_for_errors(number_of_integrations, integration_limits)?; - match self.integration_method - { - IterativeMethod::Booles => return Ok(self.get_booles(number_of_integrations, idx_to_integrate, func, integration_limits, point)), - IterativeMethod::Simpsons => return Ok(self.get_simpsons(number_of_integrations, idx_to_integrate, func, integration_limits, point)), - IterativeMethod::Trapezoidal => return Ok(self.get_trapezoidal(number_of_integrations, idx_to_integrate, func, integration_limits, point)) + match self.integration_method { + IterativeMethod::Booles => { + return Ok(self.get_booles( + number_of_integrations, + idx_to_integrate, + func, + integration_limits, + point, + )) + } + IterativeMethod::Simpsons => { + return Ok(self.get_simpsons( + number_of_integrations, + idx_to_integrate, + func, + integration_limits, + point, + )) + } + IterativeMethod::Trapezoidal => { + return Ok(self.get_trapezoidal( + number_of_integrations, + idx_to_integrate, + func, + integration_limits, + point, + )) + } } } -} \ No newline at end of file +} diff --git a/src/numerical_integration/mod.rs b/src/numerical_integration/mod.rs index e47e214..ec5e97f 100644 --- a/src/numerical_integration/mod.rs +++ b/src/numerical_integration/mod.rs @@ -1,7 +1,7 @@ -pub mod mode; +pub mod gaussian_integration; pub mod integrator; pub mod iterative_integration; -pub mod gaussian_integration; +pub mod mode; #[cfg(test)] -mod test; \ No newline at end of file +mod test; diff --git a/src/numerical_integration/mode.rs b/src/numerical_integration/mode.rs index c90d683..f230e05 100644 --- a/src/numerical_integration/mode.rs +++ b/src/numerical_integration/mode.rs @@ -1,14 +1,12 @@ #[derive(Debug, Clone, Copy)] -pub enum IterativeMethod -{ +pub enum IterativeMethod { Booles, //Highly accurate, but needs more iterations than the trapezoidal method. Good generalist method, but trapezoidal outperforms in most cases Simpsons, //Least accurate. Needs a huge number of iterations to match other methods listed here - Trapezoidal //Highly accuracate, do not need to do many iterations, best generalist out of all options + Trapezoidal, //Highly accuracate, do not need to do many iterations, best generalist out of all options } #[derive(Debug, Clone, Copy)] -pub enum GaussianQuadratureMethod -{ +pub enum GaussianQuadratureMethod { //Extremely accurate, but only recommended for polynomial equations. A specialist method with a narrow use case. GaussLegendre, @@ -17,4 +15,4 @@ pub enum GaussianQuadratureMethod //Extremely accurate, but only recommended for integrands of the form ∫exp(-X)*f(X), where f(X) is a polynomial equations. GaussLaguerre, -} \ No newline at end of file +} diff --git a/src/numerical_integration/test.rs b/src/numerical_integration/test.rs index afb4eca..62a424c 100644 --- a/src/numerical_integration/test.rs +++ b/src/numerical_integration/test.rs @@ -1,22 +1,21 @@ use crate::numerical_integration::mode::*; -use crate::numerical_integration::iterative_integration; use crate::numerical_integration::gaussian_integration; use crate::numerical_integration::integrator::*; +use crate::numerical_integration::iterative_integration; use crate::utils::error_codes::*; - + #[test] -fn test_booles_integration_1() -{ +fn test_booles_integration_1() { //equation is 2.0*x - let func = | args: f64 | -> f64 - { - return 2.0*args; + let func = |args: f64| -> f64 { + return 2.0 * args; }; let integration_limit = [0.0, 2.0]; - let integrator = iterative_integration::SingleVariableSolver::from_parameters(100, IterativeMethod::Booles); + let integrator = + iterative_integration::SingleVariableSolver::from_parameters(100, IterativeMethod::Booles); //simple integration for x, known to be x*x, expect a value of ~4.00 let val = integrator.get_single(&func, &integration_limit).unwrap(); @@ -24,50 +23,52 @@ fn test_booles_integration_1() } #[test] -fn test_booles_integration_2() -{ +fn test_booles_integration_2() { //equation is 2.0*x + y*z - let func = | args: &[f64; 3] | -> f64 - { - return 2.0*args[0] + args[1]*args[2]; + let func = |args: &[f64; 3]| -> f64 { + return 2.0 * args[0] + args[1] * args[2]; }; let integration_limit = [0.0, 1.0]; let point = [1.0, 2.0, 3.0]; - let integrator = iterative_integration::MultiVariableSolver::from_parameters(100, IterativeMethod::Booles); + let integrator = + iterative_integration::MultiVariableSolver::from_parameters(100, IterativeMethod::Booles); //partial integration for x, known to be x*x + x*y*z, expect a value of ~7.00 - let val = integrator.get_single_partial(&func, 0, &integration_limit, &point).unwrap(); + let val = integrator + .get_single_partial(&func, 0, &integration_limit, &point) + .unwrap(); assert!(f64::abs(val - 7.0) < 1e-25); - let integration_limit = [0.0, 2.0]; - //partial integration for y, known to be 2.0*x*y + y*y*z/2.0, expect a value of ~10.00 - let val = integrator.get_single_partial(&func, 1, &integration_limit, &point).unwrap(); + //partial integration for y, known to be 2.0*x*y + y*y*z/2.0, expect a value of ~10.00 + let val = integrator + .get_single_partial(&func, 1, &integration_limit, &point) + .unwrap(); assert!(f64::abs(val - 10.0) < 0.00001); - let integration_limit = [0.0, 3.0]; - //partial integration for z, known to be 2.0*x*z + y*z*z/2.0, expect a value of ~15.0 - let val = integrator.get_single_partial(&func, 2, &integration_limit, &point).unwrap(); + //partial integration for z, known to be 2.0*x*z + y*z*z/2.0, expect a value of ~15.0 + let val = integrator + .get_single_partial(&func, 2, &integration_limit, &point) + .unwrap(); assert!(f64::abs(val - 15.0) < 0.00001); } #[test] -fn test_booles_integration_3() -{ +fn test_booles_integration_3() { //equation is 6.0*x - let func = | args: f64 | -> f64 - { - return 6.0*args; + let func = |args: f64| -> f64 { + return 6.0 * args; }; let integration_limits = [[0.0, 2.0], [0.0, 2.0]]; - let integrator = iterative_integration::SingleVariableSolver::from_parameters(20, IterativeMethod::Booles); + let integrator = + iterative_integration::SingleVariableSolver::from_parameters(20, IterativeMethod::Booles); //simple double integration for 6*x, expect a value of ~24.00 let val = integrator.get_double(&func, &integration_limits).unwrap(); @@ -75,67 +76,74 @@ fn test_booles_integration_3() } #[test] -fn test_gauss_legendre_quadrature_integration_1() -{ +fn test_gauss_legendre_quadrature_integration_1() { //equation is 4.0*x*x*x - 3.0*x*x - let func = | args: f64 | -> f64 - { - return 4.0*args*args*args - 3.0*args*args; + let func = |args: f64| -> f64 { + return 4.0 * args * args * args - 3.0 * args * args; }; let integration_limit = [0.0, 2.0]; - let integrator = gaussian_integration::SingleVariableSolver::from_parameters(4, GaussianQuadratureMethod::GaussLegendre); + let integrator = gaussian_integration::SingleVariableSolver::from_parameters( + 4, + GaussianQuadratureMethod::GaussLegendre, + ); //simple integration for x, known to be x^4 - x^3, expect a value of ~8.00 let val = integrator.get_single(&func, &integration_limit).unwrap(); assert!(f64::abs(val - 8.0) < 1e-14); } -#[test] -fn test_gauss_legendre_quadrature_integration_2() -{ +#[test] +fn test_gauss_legendre_quadrature_integration_2() { //equation is 2.0*x + y*z - let func = | args: &[f64; 3] | -> f64 - { - return 2.0*args[0] + args[1]*args[2]; + let func = |args: &[f64; 3]| -> f64 { + return 2.0 * args[0] + args[1] * args[2]; }; let integration_limit = [0.0, 1.0]; let point = [1.0, 2.0, 3.0]; - let integrator = gaussian_integration::MultiVariableSolver::from_parameters(2, GaussianQuadratureMethod::GaussLegendre); + let integrator = gaussian_integration::MultiVariableSolver::from_parameters( + 2, + GaussianQuadratureMethod::GaussLegendre, + ); //partial integration for x, known to be x*x + x*y*z, expect a value of ~7.00 - let val = integrator.get_single_partial(&func, 0, &integration_limit, &point).unwrap(); + let val = integrator + .get_single_partial(&func, 0, &integration_limit, &point) + .unwrap(); assert!(f64::abs(val - 7.0) < 1e-14); - let integration_limit = [0.0, 2.0]; - //partial integration for y, known to be 2.0*x*y + y*y*z/2.0, expect a value of ~10.00 - let val = integrator.get_single_partial(&func, 1, &integration_limit, &point).unwrap(); + //partial integration for y, known to be 2.0*x*y + y*y*z/2.0, expect a value of ~10.00 + let val = integrator + .get_single_partial(&func, 1, &integration_limit, &point) + .unwrap(); assert!(f64::abs(val - 10.0) < 1e-14); - let integration_limit = [0.0, 3.0]; - //partial integration for z, known to be 2.0*x*z + y*z*z/2.0, expect a value of ~15.0 - let val = integrator.get_single_partial(&func, 2, &integration_limit, &point).unwrap(); + //partial integration for z, known to be 2.0*x*z + y*z*z/2.0, expect a value of ~15.0 + let val = integrator + .get_single_partial(&func, 2, &integration_limit, &point) + .unwrap(); assert!(f64::abs(val - 15.0) < 1e-14); } #[test] -fn test_gauss_legendre_quadrature_integration_3() -{ +fn test_gauss_legendre_quadrature_integration_3() { //equation is 6.0*x - let func = | args: f64 | -> f64 - { - return 6.0*args; + let func = |args: f64| -> f64 { + return 6.0 * args; }; let integration_limits = [[0.0, 2.0], [0.0, 2.0]]; - let integrator = gaussian_integration::SingleVariableSolver::from_parameters(2, GaussianQuadratureMethod::GaussLegendre); + let integrator = gaussian_integration::SingleVariableSolver::from_parameters( + 2, + GaussianQuadratureMethod::GaussLegendre, + ); //simple double integration for 6*x, expect a value of ~24.00 let val = integrator.get_double(&func, &integration_limits).unwrap(); @@ -143,17 +151,18 @@ fn test_gauss_legendre_quadrature_integration_3() } #[test] -fn test_simpsons_integration_1() -{ +fn test_simpsons_integration_1() { //equation is 2.0*x - let func = | args: f64 | -> f64 - { - return 2.0*args; + let func = |args: f64| -> f64 { + return 2.0 * args; }; let integration_limit = [0.0, 2.0]; - let integrator = iterative_integration::SingleVariableSolver::from_parameters(200, IterativeMethod::Simpsons); + let integrator = iterative_integration::SingleVariableSolver::from_parameters( + 200, + IterativeMethod::Simpsons, + ); //simple integration for x, known to be x*x, expect a value of ~4.00 let val = integrator.get_single(&func, &integration_limit).unwrap(); @@ -161,50 +170,54 @@ fn test_simpsons_integration_1() } #[test] -fn test_simpsons_integration_2() -{ +fn test_simpsons_integration_2() { //equation is 2.0*x + y*z - let func = | args: &[f64; 3] | -> f64 - { - return 2.0*args[0] + args[1]*args[2]; + let func = |args: &[f64; 3]| -> f64 { + return 2.0 * args[0] + args[1] * args[2]; }; let integration_limit = [0.0, 1.0]; let point = [1.0, 2.0, 3.0]; - let integrator = iterative_integration::MultiVariableSolver::from_parameters(200, IterativeMethod::Simpsons); + let integrator = + iterative_integration::MultiVariableSolver::from_parameters(200, IterativeMethod::Simpsons); //partial integration for x, known to be x*x + x*y*z, expect a value of ~7.00 - let val = integrator.get_single_partial(&func, 0, &integration_limit, &point).unwrap(); + let val = integrator + .get_single_partial(&func, 0, &integration_limit, &point) + .unwrap(); assert!(f64::abs(val - 7.0) < 0.05); - let integration_limit = [0.0, 2.0]; - //partial integration for y, known to be 2.0*x*y + y*y*z/2.0, expect a value of ~10.00 - let val = integrator.get_single_partial(&func, 1, &integration_limit, &point).unwrap(); + //partial integration for y, known to be 2.0*x*y + y*y*z/2.0, expect a value of ~10.00 + let val = integrator + .get_single_partial(&func, 1, &integration_limit, &point) + .unwrap(); assert!(f64::abs(val - 10.0) < 0.05); - let integration_limit = [0.0, 3.0]; - //partial integration for z, known to be 2.0*x*z + y*z*z/2.0, expect a value of ~15.0 - let val = integrator.get_single_partial(&func, 2, &integration_limit, &point).unwrap(); + //partial integration for z, known to be 2.0*x*z + y*z*z/2.0, expect a value of ~15.0 + let val = integrator + .get_single_partial(&func, 2, &integration_limit, &point) + .unwrap(); assert!(f64::abs(val - 15.0) < 0.05); } #[test] -fn test_simpsons_integration_3() -{ +fn test_simpsons_integration_3() { //equation is 6.0*x - let func = | args: f64 | -> f64 - { - return 6.0*args; + let func = |args: f64| -> f64 { + return 6.0 * args; }; let integration_limits = [[0.0, 2.0], [0.0, 2.0]]; - let integrator = iterative_integration::SingleVariableSolver::from_parameters(200, IterativeMethod::Simpsons); + let integrator = iterative_integration::SingleVariableSolver::from_parameters( + 200, + IterativeMethod::Simpsons, + ); //simple double integration for 6*x, expect a value of ~24.00 let val = integrator.get_double(&func, &integration_limits).unwrap(); @@ -212,86 +225,94 @@ fn test_simpsons_integration_3() } #[test] -fn test_simpsons_integration_4() -{ +fn test_simpsons_integration_4() { //equation is 2.0*x + y*z - let func = | args: &[f64; 3] | -> f64 - { - return 2.0*args[0] + args[1]*args[2]; + let func = |args: &[f64; 3]| -> f64 { + return 2.0 * args[0] + args[1] * args[2]; }; let integration_limits = [[0.0, 1.0], [0.0, 1.0]]; let point = [1.0, 1.0, 1.0]; - let integrator = iterative_integration::MultiVariableSolver::from_parameters(200, IterativeMethod::Simpsons); + let integrator = + iterative_integration::MultiVariableSolver::from_parameters(200, IterativeMethod::Simpsons); //double partial integration for first x then y, expect a value of ~1.50 - let val = integrator.get_double_partial(&func, [0, 1], &integration_limits, &point).unwrap(); + let val = integrator + .get_double_partial(&func, [0, 1], &integration_limits, &point) + .unwrap(); assert!(f64::abs(val - 1.50) < 0.05); } #[test] -fn test_trapezoidal_integration_1() -{ +fn test_trapezoidal_integration_1() { //equation is 2.0*x - let func = | args: f64 | -> f64 - { - return 2.0*args; + let func = |args: f64| -> f64 { + return 2.0 * args; }; let integration_limit = [0.0, 2.0]; - let iterator = iterative_integration::SingleVariableSolver::from_parameters(100, IterativeMethod::Trapezoidal); + let iterator = iterative_integration::SingleVariableSolver::from_parameters( + 100, + IterativeMethod::Trapezoidal, + ); let val = iterator.get_single(&func, &integration_limit).unwrap(); assert!(f64::abs(val - 4.0) < 0.00001); } #[test] -fn test_trapezoidal_integration_2() -{ +fn test_trapezoidal_integration_2() { //equation is 2.0*x + y*z - let func = | args: &[f64; 3] | -> f64 - { - return 2.0*args[0] + args[1]*args[2]; + let func = |args: &[f64; 3]| -> f64 { + return 2.0 * args[0] + args[1] * args[2]; }; let integration_limit = [0.0, 1.0]; let point = [1.0, 2.0, 3.0]; - let iterator = iterative_integration::MultiVariableSolver::from_parameters(100, IterativeMethod::Trapezoidal); + let iterator = iterative_integration::MultiVariableSolver::from_parameters( + 100, + IterativeMethod::Trapezoidal, + ); //partial integration for x, known to be x*x + x*y*z, expect a value of ~7.00 - let val = iterator.get_single_partial(&func, 0, &integration_limit, &point).unwrap(); + let val = iterator + .get_single_partial(&func, 0, &integration_limit, &point) + .unwrap(); assert!(f64::abs(val - 7.0) < 0.00001); - let integration_limit = [0.0, 2.0]; - //partial integration for y, known to be 2.0*x*y + y*y*z/2.0, expect a value of ~10.00 - let val = iterator.get_single_partial(&func, 1, &integration_limit, &point).unwrap(); + //partial integration for y, known to be 2.0*x*y + y*y*z/2.0, expect a value of ~10.00 + let val = iterator + .get_single_partial(&func, 1, &integration_limit, &point) + .unwrap(); assert!(f64::abs(val - 10.0) < 0.00001); - let integration_limit = [0.0, 3.0]; - //partial integration for z, known to be 2.0*x*z + y*z*z/2.0, expect a value of ~15.0 - let val = iterator.get_single_partial(&func, 2, &integration_limit, &point).unwrap(); + //partial integration for z, known to be 2.0*x*z + y*z*z/2.0, expect a value of ~15.0 + let val = iterator + .get_single_partial(&func, 2, &integration_limit, &point) + .unwrap(); assert!(f64::abs(val - 15.0) < 0.00001); } #[test] -fn test_trapezoidal_integration_3() -{ +fn test_trapezoidal_integration_3() { //equation is 6.0*x - let func = | args: f64 | -> f64 - { - return 6.0*args; + let func = |args: f64| -> f64 { + return 6.0 * args; }; let integration_limits = [[0.0, 2.0], [0.0, 2.0]]; - let integrator = iterative_integration::SingleVariableSolver::from_parameters(10, IterativeMethod::Trapezoidal); + let integrator = iterative_integration::SingleVariableSolver::from_parameters( + 10, + IterativeMethod::Trapezoidal, + ); //simple double integration for 6*x, expect a value of ~24.00 let val = integrator.get_double(&func, &integration_limits).unwrap(); @@ -299,31 +320,32 @@ fn test_trapezoidal_integration_3() } #[test] -fn test_trapezoidal_integration_4() -{ +fn test_trapezoidal_integration_4() { //equation is 2.0*x + y*z - let func = | args: &[f64; 3] | -> f64 - { - return 2.0*args[0] + args[1]*args[2]; + let func = |args: &[f64; 3]| -> f64 { + return 2.0 * args[0] + args[1] * args[2]; }; let integration_limits = [[0.0, 1.0], [0.0, 2.0]]; let point = [1.0, 2.0, 3.0]; - let integrator = iterative_integration::MultiVariableSolver::from_parameters(10, IterativeMethod::Trapezoidal); + let integrator = iterative_integration::MultiVariableSolver::from_parameters( + 10, + IterativeMethod::Trapezoidal, + ); //double partial integration for first x then y, expect a value of ~2.50 - let val = integrator.get_double_partial(&func, [0, 1], &integration_limits, &point).unwrap(); + let val = integrator + .get_double_partial(&func, [0, 1], &integration_limits, &point) + .unwrap(); assert!(f64::abs(val - 8.0) < 0.00001); } #[test] -fn test_error_checking_1() -{ +fn test_error_checking_1() { //equation is 2.0*x - let func = | args: f64 | -> f64 - { - return 2.0*args; + let func = |args: f64| -> f64 { + return 2.0 * args; }; let integration_limit = [10.0, 1.0]; @@ -337,17 +359,16 @@ fn test_error_checking_1() } #[test] -fn test_error_checking_2() -{ +fn test_error_checking_2() { //equation is 2.0*x - let func = | args: f64 | -> f64 - { - return 2.0*args; + let func = |args: f64| -> f64 { + return 2.0 * args; }; let integration_limit = [0.0, 1.0]; - let integrator = iterative_integration::SingleVariableSolver::from_parameters(0, IterativeMethod::Booles); + let integrator = + iterative_integration::SingleVariableSolver::from_parameters(0, IterativeMethod::Booles); //expect failure because number of steps is 0 let result = integrator.get_single(&func, &integration_limit); @@ -358,37 +379,39 @@ fn test_error_checking_2() //TODO: add more tests #[test] -fn test_error_checking_3() -{ +fn test_error_checking_3() { //equation is 4.0*x*x*x - 3.0*x*x - let func = | args: f64 | -> f64 - { - return 4.0*args*args*args - 3.0*args*args; + let func = |args: f64| -> f64 { + return 4.0 * args * args * args - 3.0 * args * args; }; let integration_limit = [0.0, 2.0]; //Gauss Legendre not valid for n < 1 - let integrator = gaussian_integration::SingleVariableSolver::from_parameters(0, GaussianQuadratureMethod::GaussLegendre); + let integrator = gaussian_integration::SingleVariableSolver::from_parameters( + 0, + GaussianQuadratureMethod::GaussLegendre, + ); let result = integrator.get_single(&func, &integration_limit); assert!(result.is_err()); assert!(result.unwrap_err() == GAUSSIAN_QUADRATURE_ORDER_OUT_OF_RANGE); } #[test] -fn test_error_checking_4() -{ +fn test_error_checking_4() { //equation is 4.0*x*x*x - 3.0*x*x - let func = | args: f64 | -> f64 - { - return 4.0*args*args*args - 3.0*args*args; + let func = |args: f64| -> f64 { + return 4.0 * args * args * args - 3.0 * args * args; }; let integration_limit = [0.0, 2.0]; //Gauss Legendre not valid for n > 30 - let integrator = gaussian_integration::SingleVariableSolver::from_parameters(31, GaussianQuadratureMethod::GaussLegendre); + let integrator = gaussian_integration::SingleVariableSolver::from_parameters( + 31, + GaussianQuadratureMethod::GaussLegendre, + ); let result = integrator.get_single(&func, &integration_limit); assert!(result.is_err()); assert!(result.unwrap_err() == GAUSSIAN_QUADRATURE_ORDER_OUT_OF_RANGE); -} \ No newline at end of file +} diff --git a/src/utils/error_codes.rs b/src/utils/error_codes.rs index 5f20d37..9dbdea9 100644 --- a/src/utils/error_codes.rs +++ b/src/utils/error_codes.rs @@ -1,11 +1,18 @@ -pub const NUMBER_OF_DERIVATIVE_STEPS_CANNOT_BE_ZERO: &str = "Cannot specify the step size for differentiation as zero!"; -pub const DERIVATE_ORDER_CANNOT_BE_ZERO: &str = "The 'order' argument for computing the derivative cannot be zero!"; -pub const INDEX_TO_DERIVATE_ILL_FORMED: &str = "The 'idx_to_derivate' argument length must match exactly with the 'order' argument!"; +pub const NUMBER_OF_DERIVATIVE_STEPS_CANNOT_BE_ZERO: &str = + "Cannot specify the step size for differentiation as zero!"; +pub const DERIVATE_ORDER_CANNOT_BE_ZERO: &str = + "The 'order' argument for computing the derivative cannot be zero!"; +pub const INDEX_TO_DERIVATE_ILL_FORMED: &str = + "The 'idx_to_derivate' argument length must match exactly with the 'order' argument!"; pub const INDEX_TO_DERIVATIVE_OUT_OF_RANGE: &str = "One of the values in 'idx_to_derivate' argument is greater than the length of 'point' argument!"; -pub const INTEGRATION_CANNOT_HAVE_ZERO_ITERATIONS: &str = "Total number of iterations cannot be zero!"; +pub const INTEGRATION_CANNOT_HAVE_ZERO_ITERATIONS: &str = + "Total number of iterations cannot be zero!"; pub const INCORRECT_NUMBER_OF_INTEGRATION_LIMITS: &str = "The 'number_of_integrations' argument value must match the length of 'integration_limit' exactly!"; -pub const INTEGRATION_LIMITS_ILL_DEFINED: &str = "Each lower integration limit must be strictly less than its upper limit!"; -pub const GAUSSIAN_QUADRATURE_ORDER_OUT_OF_RANGE: &str = "Gaussian Quadrature for this order is not supported!"; +pub const INTEGRATION_LIMITS_ILL_DEFINED: &str = + "Each lower integration limit must be strictly less than its upper limit!"; +pub const GAUSSIAN_QUADRATURE_ORDER_OUT_OF_RANGE: &str = + "Gaussian Quadrature for this order is not supported!"; -pub const VECTOR_OF_FUNCTIONS_CANNOT_BE_EMPTY: &str = "Cannot pass in an empty 'function_matrix' argument!"; \ No newline at end of file +pub const VECTOR_OF_FUNCTIONS_CANNOT_BE_EMPTY: &str = + "Cannot pass in an empty 'function_matrix' argument!"; diff --git a/src/utils/gauss_laguerre_table.rs b/src/utils/gauss_laguerre_table.rs index b7d7524..4520ff7 100644 --- a/src/utils/gauss_laguerre_table.rs +++ b/src/utils/gauss_laguerre_table.rs @@ -2,11 +2,11 @@ use crate::utils::error_codes::GAUSSIAN_QUADRATURE_ORDER_OUT_OF_RANGE; pub const MAX_GH_ORDER: usize = 30; - -pub fn get_gauss_laguerre_weights_and_abscissae(order: usize, index: usize) -> Result<(f64, f64), &'static str> -{ - let ref_abs: f64 = match order - { +pub fn get_gauss_laguerre_weights_and_abscissae( + order: usize, + index: usize, +) -> Result<(f64, f64), &'static str> { + let ref_abs: f64 = match order { 1 => LAGUERRE_ABSCISSA_1[index], 2 => LAGUERRE_ABSCISSA_2[index], 3 => LAGUERRE_ABSCISSA_3[index], @@ -40,8 +40,7 @@ pub fn get_gauss_laguerre_weights_and_abscissae(order: usize, index: usize) -> R _ => return Err(GAUSSIAN_QUADRATURE_ORDER_OUT_OF_RANGE), }; - let ref_weight: f64 = match order - { + let ref_weight: f64 = match order { 1 => LAGUERRE_WEIGHT_1[index], 2 => LAGUERRE_WEIGHT_2[index], 3 => LAGUERRE_WEIGHT_3[index], @@ -81,994 +80,1036 @@ pub fn get_gauss_laguerre_weights_and_abscissae(order: usize, index: usize) -> R // ============================================================================= // Table generated using Python's numpy.polynomial.laguerre // ============================================================================= -const LAGUERRE_ABSCISSA_1: [f64; 1] = [ -1.0]; -const LAGUERRE_ABSCISSA_2: [f64; 2] = [ -0.585786437626905, -3.414213562373095]; -const LAGUERRE_ABSCISSA_3: [f64; 3] = [ -0.4157745567834791, -2.294280360279042, -6.2899450829374794]; +const LAGUERRE_ABSCISSA_1: [f64; 1] = [1.0]; +const LAGUERRE_ABSCISSA_2: [f64; 2] = [0.585786437626905, 3.414213562373095]; +const LAGUERRE_ABSCISSA_3: [f64; 3] = [0.4157745567834791, 2.294280360279042, 6.2899450829374794]; const LAGUERRE_ABSCISSA_4: [f64; 4] = [ -0.3225476896193924, -1.7457611011583465, -4.536620296921128, -9.395070912301133]; + 0.3225476896193924, + 1.7457611011583465, + 4.536620296921128, + 9.395070912301133, +]; const LAGUERRE_ABSCISSA_5: [f64; 5] = [ -0.26356031971814087, -1.4134030591065168, -3.596425771040722, -7.085810005858837, -12.640800844275782]; + 0.26356031971814087, + 1.4134030591065168, + 3.596425771040722, + 7.085810005858837, + 12.640800844275782, +]; const LAGUERRE_ABSCISSA_6: [f64; 6] = [ -0.2228466041792607, -1.1889321016726226, -2.992736326059314, -5.77514356910451, -9.83746741838259, -15.982873980601703]; + 0.2228466041792607, + 1.1889321016726226, + 2.992736326059314, + 5.77514356910451, + 9.83746741838259, + 15.982873980601703, +]; const LAGUERRE_ABSCISSA_7: [f64; 7] = [ -0.19304367656036225, -1.0266648953391924, -2.567876744950746, -4.900353084526484, -8.18215344456286, -12.734180291797815, -19.39572786226254]; + 0.19304367656036225, + 1.0266648953391924, + 2.567876744950746, + 4.900353084526484, + 8.18215344456286, + 12.734180291797815, + 19.39572786226254, +]; const LAGUERRE_ABSCISSA_8: [f64; 8] = [ -0.17027963230510093, -0.90370177679938, -2.251086629866131, -4.266700170287659, -7.0459054023934655, -10.758516010180996, -15.740678641278004, -22.863131736889265]; + 0.17027963230510093, + 0.90370177679938, + 2.251086629866131, + 4.266700170287659, + 7.0459054023934655, + 10.758516010180996, + 15.740678641278004, + 22.863131736889265, +]; const LAGUERRE_ABSCISSA_9: [f64; 9] = [ -0.1523222277318084, -0.8072200227422562, -2.005135155619347, -3.783473973331233, -6.204956777876613, -9.372985251687576, -13.466236911092095, -18.833597788991696, -26.374071890927375]; + 0.1523222277318084, + 0.8072200227422562, + 2.005135155619347, + 3.783473973331233, + 6.204956777876613, + 9.372985251687576, + 13.466236911092095, + 18.833597788991696, + 26.374071890927375, +]; const LAGUERRE_ABSCISSA_10: [f64; 10] = [ -0.1377934705404926, -0.729454549503171, -1.8083429017403159, -3.4014336978548996, -5.552496140063804, -8.330152746764497, -11.843785837900066, -16.279257831378104, -21.99658581198076, -29.92069701227389]; + 0.1377934705404926, + 0.729454549503171, + 1.8083429017403159, + 3.4014336978548996, + 5.552496140063804, + 8.330152746764497, + 11.843785837900066, + 16.279257831378104, + 21.99658581198076, + 29.92069701227389, +]; const LAGUERRE_ABSCISSA_11: [f64; 11] = [ -0.12579644218796757, -0.6654182558392279, -1.6471505458721691, -3.091138143035255, -5.029284401579833, -7.509887863806617, -10.605950999546968, -14.431613758064186, -19.17885740321468, -25.217709339677562, -33.49719284717553]; + 0.12579644218796757, + 0.6654182558392279, + 1.6471505458721691, + 3.091138143035255, + 5.029284401579833, + 7.509887863806617, + 10.605950999546968, + 14.431613758064186, + 19.17885740321468, + 25.217709339677562, + 33.49719284717553, +]; const LAGUERRE_ABSCISSA_12: [f64; 12] = [ -0.1157221173580205, -0.6117574845151308, -1.512610269776419, -2.833751337743507, -4.5992276394183484, -6.844525453115177, -9.621316842456867, -13.006054993306348, -17.116855187462257, -22.151090379397004, -28.487967250984, -37.09912104446692]; + 0.1157221173580205, + 0.6117574845151308, + 1.512610269776419, + 2.833751337743507, + 4.5992276394183484, + 6.844525453115177, + 9.621316842456867, + 13.006054993306348, + 17.116855187462257, + 22.151090379397004, + 28.487967250984, + 37.09912104446692, +]; const LAGUERRE_ABSCISSA_13: [f64; 13] = [ -0.10714238847225208, -0.5661318990404021, -1.3985643364510194, -2.616597108406411, -4.2388459290170335, -6.292256271140074, -8.815001941186978, -11.861403588811243, -15.510762037703753, -19.88463566388023, -25.185263864677758, -31.800386301947267, -40.72300866926558]; + 0.10714238847225208, + 0.5661318990404021, + 1.3985643364510194, + 2.616597108406411, + 4.2388459290170335, + 6.292256271140074, + 8.815001941186978, + 11.861403588811243, + 15.510762037703753, + 19.88463566388023, + 25.185263864677758, + 31.800386301947267, + 40.72300866926558, +]; const LAGUERRE_ABSCISSA_14: [f64; 14] = [ -0.09974750703259747, -0.5268576488519032, -1.3006291212514964, -2.4308010787308443, -3.9321028222932184, -5.825536218301709, -8.140240141565144, -10.91649950736602, -14.21080501116129, -18.104892220218098, -22.723381628269625, -28.272981723248204, -35.149443660592425, -44.366081711117424]; + 0.09974750703259747, + 0.5268576488519032, + 1.3006291212514964, + 2.4308010787308443, + 3.9321028222932184, + 5.825536218301709, + 8.140240141565144, + 10.91649950736602, + 14.21080501116129, + 18.104892220218098, + 22.723381628269625, + 28.272981723248204, + 35.149443660592425, + 44.366081711117424, +]; const LAGUERRE_ABSCISSA_15: [f64; 15] = [ -0.09330781201728192, -0.4926917403018839, -1.2155954120709496, -2.2699495262037437, -3.667622721751437, -5.425336627413554, -7.565916226613068, -10.120228568019114, -13.130282482175724, -16.65440770832996, -20.77647889944877, -25.62389422672878, -31.40751916975394, -38.53068330648601, -48.026085572685794]; + 0.09330781201728192, + 0.4926917403018839, + 1.2155954120709496, + 2.2699495262037437, + 3.667622721751437, + 5.425336627413554, + 7.565916226613068, + 10.120228568019114, + 13.130282482175724, + 16.65440770832996, + 20.77647889944877, + 25.62389422672878, + 31.40751916975394, + 38.53068330648601, + 48.026085572685794, +]; const LAGUERRE_ABSCISSA_16: [f64; 16] = [ -0.08764941047892776, -0.4626963289150804, -1.1410577748312265, -2.1292836450983805, -3.4370866338932067, -5.078018614549768, -7.070338535048234, -9.438314336391938, -12.21422336886616, -15.441527368781617, -19.180156856753136, -23.515905693991908, -28.57872974288214, -34.58339870228662, -41.94045264768833, -51.70116033954332]; + 0.08764941047892776, + 0.4626963289150804, + 1.1410577748312265, + 2.1292836450983805, + 3.4370866338932067, + 5.078018614549768, + 7.070338535048234, + 9.438314336391938, + 12.21422336886616, + 15.441527368781617, + 19.180156856753136, + 23.515905693991908, + 28.57872974288214, + 34.58339870228662, + 41.94045264768833, + 51.70116033954332, +]; const LAGUERRE_ABSCISSA_17: [f64; 17] = [ -0.08263821470894772, -0.43615032355871114, -1.075176577511429, -2.0051935316492315, -3.2342561240474432, -4.7735135137001965, -6.637829205364953, -8.8466855111698, -11.425529319373354, -14.407823037481318, -17.83828473070114, -21.778268257722267, -26.3153178112488, -31.581771680456733, -37.7960938374771, -45.375716533988964, -55.389751789839615]; + 0.08263821470894772, + 0.43615032355871114, + 1.075176577511429, + 2.0051935316492315, + 3.2342561240474432, + 4.7735135137001965, + 6.637829205364953, + 8.8466855111698, + 11.425529319373354, + 14.407823037481318, + 17.83828473070114, + 21.778268257722267, + 26.3153178112488, + 31.581771680456733, + 37.7960938374771, + 45.375716533988964, + 55.389751789839615, +]; const LAGUERRE_ABSCISSA_18: [f64; 18] = [ -0.07816916666970553, -0.4124900852591291, -1.0165201796235392, -1.894888509969761, -3.05435311320266, -4.5042055388898925, -6.256725073949111, -8.32782515660563, -10.73799004775761, -13.51365620755509, -16.689306281930104, -20.310767626267744, -24.4406813592837, -29.168208662579616, -34.627927065660174, -41.04181677280876, -48.83392271608652, -59.09054643590125]; + 0.07816916666970553, + 0.4124900852591291, + 1.0165201796235392, + 1.894888509969761, + 3.05435311320266, + 4.5042055388898925, + 6.256725073949111, + 8.32782515660563, + 10.73799004775761, + 13.51365620755509, + 16.689306281930104, + 20.310767626267744, + 24.4406813592837, + 29.168208662579616, + 34.627927065660174, + 41.04181677280876, + 48.83392271608652, + 59.09054643590125, +]; const LAGUERRE_ABSCISSA_19: [f64; 19] = [ -0.07415878375720486, -0.391268613319995, -0.9639573439979584, -1.796175582068328, -2.893651381873784, -4.264215539627767, -5.918141561644048, -7.868618915334735, -10.132423716815266, -12.730881463842397, -15.691278339835888, -19.04899320982355, -22.850849760829483, -27.160669327411448, -32.06912225186224, -37.71290580121965, -44.3173627958315, -52.312902457404384, -62.80242315350038]; + 0.07415878375720486, + 0.391268613319995, + 0.9639573439979584, + 1.796175582068328, + 2.893651381873784, + 4.264215539627767, + 5.918141561644048, + 7.868618915334735, + 10.132423716815266, + 12.730881463842397, + 15.691278339835888, + 19.04899320982355, + 22.850849760829483, + 27.160669327411448, + 32.06912225186224, + 37.71290580121965, + 44.3173627958315, + 52.312902457404384, + 62.80242315350038, +]; const LAGUERRE_ABSCISSA_20: [f64; 20] = [ -0.07053988969198874, -0.37212681800161157, -0.9165821024832738, -1.7073065310283435, -2.749199255309432, -4.048925313850888, -5.615174970861617, -7.459017453671063, -9.594392869581098, -12.038802546964316, -14.81429344263074, -17.948895520519375, -21.47878824028501, -25.451702793186904, -29.93255463170061, -35.013434240479, -40.83305705672857, -47.6199940473465, -55.810795750063896, -66.52441652561575]; + 0.07053988969198874, + 0.37212681800161157, + 0.9165821024832738, + 1.7073065310283435, + 2.749199255309432, + 4.048925313850888, + 5.615174970861617, + 7.459017453671063, + 9.594392869581098, + 12.038802546964316, + 14.81429344263074, + 17.948895520519375, + 21.47878824028501, + 25.451702793186904, + 29.93255463170061, + 35.013434240479, + 40.83305705672857, + 47.6199940473465, + 55.810795750063896, + 66.52441652561575, +]; const LAGUERRE_ABSCISSA_21: [f64; 21] = [ -0.06725781792316145, -0.35477289532351297, -0.8736601667786427, -1.62686994192921, -2.6186264105455432, -3.85465213810976, -5.342369280622434, -7.091168813219674, -9.112778854269706, -11.421771762378382, -14.036270697873759, -16.97895269278384, -20.278509414993742, -23.971845587151478, -28.107528600944306, -32.75149741056083, -37.99718781926095, -43.985245757142216, -50.94735118993992, -59.32599412022999, -70.25568862801893]; + 0.06725781792316145, + 0.35477289532351297, + 0.8736601667786427, + 1.62686994192921, + 2.6186264105455432, + 3.85465213810976, + 5.342369280622434, + 7.091168813219674, + 9.112778854269706, + 11.421771762378382, + 14.036270697873759, + 16.97895269278384, + 20.278509414993742, + 23.971845587151478, + 28.107528600944306, + 32.75149741056083, + 37.99718781926095, + 43.985245757142216, + 50.94735118993992, + 59.32599412022999, + 70.25568862801893, +]; const LAGUERRE_ABSCISSA_22: [f64; 22] = [ -0.06426762874480897, -0.3389672548149106, -0.8345899854491785, -1.5537133867500255, -2.500006236736173, -3.678420344463637, -5.095349068968738, -6.75883551581355, -8.678853313678427, -10.86768689354057, -13.34045105149524, -16.11581133876631, -19.217003684901353, -22.67331660143459, -26.52231958763714, -30.81335794450656, -35.61333520319617, -41.016968598471685, -47.16675784915352, -54.297385256578885, -62.85709624629903, -73.9955070085995]; + 0.06426762874480897, + 0.3389672548149106, + 0.8345899854491785, + 1.5537133867500255, + 2.500006236736173, + 3.678420344463637, + 5.095349068968738, + 6.75883551581355, + 8.678853313678427, + 10.86768689354057, + 13.34045105149524, + 16.11581133876631, + 19.217003684901353, + 22.67331660143459, + 26.52231958763714, + 30.81335794450656, + 35.61333520319617, + 41.016968598471685, + 47.16675784915352, + 54.297385256578885, + 62.85709624629903, + 73.9955070085995, +]; const LAGUERRE_ABSCISSA_23: [f64; 23] = [ -0.06153203775752009, -0.3245113291545522, -0.7988739686929834, -1.4868863342221967, -2.391755829792768, -3.5177974425035337, -4.870560368733452, -6.4569913067677405, -8.285651892598002, -10.367009043445767, -12.713825028162594, -15.341687572888508, -18.26974239389599, -21.521727850814163, -25.127477130115498, -29.125175108751016, -33.56489656311642, -38.51445967718072, -44.06980781487121, -50.37522660304375, -57.66830435043413, -66.40287306834517, -77.74322728471232]; + 0.06153203775752009, + 0.3245113291545522, + 0.7988739686929834, + 1.4868863342221967, + 2.391755829792768, + 3.5177974425035337, + 4.870560368733452, + 6.4569913067677405, + 8.285651892598002, + 10.367009043445767, + 12.713825028162594, + 15.341687572888508, + 18.26974239389599, + 21.521727850814163, + 25.127477130115498, + 29.125175108751016, + 33.56489656311642, + 38.51445967718072, + 44.06980781487121, + 50.37522660304375, + 57.66830435043413, + 66.40287306834517, + 77.74322728471232, +]; const LAGUERRE_ABSCISSA_24: [f64; 24] = [ -0.05901985218150761, -0.3112391461984835, -0.7660969055459361, -1.4255975908036125, -2.2925620586321904, -3.3707742642089986, -4.66508370346717, -6.181535118736765, -7.927539247172152, -9.912098015077705, -12.146102711729764, -14.642732289596674, -17.417992646508978, -20.491460082616424, -23.887329848169735, -27.635937174332717, -31.776041352374722, -36.35840580165162, -41.45172048487077, -47.153106445156325, -53.60857454469507, -61.05853144721876, -69.96224003510503, -81.49827923394889]; + 0.05901985218150761, + 0.3112391461984835, + 0.7660969055459361, + 1.4255975908036125, + 2.2925620586321904, + 3.3707742642089986, + 4.66508370346717, + 6.181535118736765, + 7.927539247172152, + 9.912098015077705, + 12.146102711729764, + 14.642732289596674, + 17.417992646508978, + 20.491460082616424, + 23.887329848169735, + 27.635937174332717, + 31.776041352374722, + 36.35840580165162, + 41.45172048487077, + 47.153106445156325, + 53.60857454469507, + 61.05853144721876, + 69.96224003510503, + 81.49827923394889, +]; const LAGUERRE_ABSCISSA_25: [f64; 25] = [ -0.05670477545270528, -0.29901089858698887, -0.7359095554350165, -1.369183116035193, -2.2013260537214667, -3.235675803558037, -4.476496615073835, -5.929083762700448, -7.599899309956751, -9.496749220932434, -11.629014911778754, -14.007957976545068, -16.647125597288785, -19.562898011469056, -22.77524198683504, -26.308772390968887, -30.194291163316105, -34.47109757192204, -39.19060880393742, -44.42234933616202, -50.26457499383354, -56.86496717394018, -64.46667061595413, -73.53423479210015, -85.26015556249595]; + 0.05670477545270528, + 0.29901089858698887, + 0.7359095554350165, + 1.369183116035193, + 2.2013260537214667, + 3.235675803558037, + 4.476496615073835, + 5.929083762700448, + 7.599899309956751, + 9.496749220932434, + 11.629014911778754, + 14.007957976545068, + 16.647125597288785, + 19.562898011469056, + 22.77524198683504, + 26.308772390968887, + 30.194291163316105, + 34.47109757192204, + 39.19060880393742, + 44.42234933616202, + 50.26457499383354, + 56.86496717394018, + 64.46667061595413, + 73.53423479210015, + 85.26015556249595, +]; const LAGUERRE_ABSCISSA_26: [f64; 26] = [ -0.054564482717908286, -0.2877079791061228, -0.7080160194786457, -1.3170813660438436, -2.11712094462847, -3.1110938788779334, -4.302770876040371, -5.6968188261694666, -7.298909963070183, -9.115862897294216, -11.15582495493751, -13.428509032459203, -15.945503948143319, -18.720686145460284, -21.770774608541437, -25.11609366231674, -28.781646873450168, -32.798673218409974, -37.206982629612824, -42.058615924434534, -47.42389935628153, -53.40218519725329, -60.142775690076896, -67.89147970545129, -77.11799906933285, -89.02840275041098]; + 0.054564482717908286, + 0.2877079791061228, + 0.7080160194786457, + 1.3170813660438436, + 2.11712094462847, + 3.1110938788779334, + 4.302770876040371, + 5.6968188261694666, + 7.298909963070183, + 9.115862897294216, + 11.15582495493751, + 13.428509032459203, + 15.945503948143319, + 18.720686145460284, + 21.770774608541437, + 25.11609366231674, + 28.781646873450168, + 32.798673218409974, + 37.206982629612824, + 42.058615924434534, + 47.42389935628153, + 53.40218519725329, + 60.142775690076896, + 67.89147970545129, + 77.11799906933285, + 89.02840275041098, +]; const LAGUERRE_ABSCISSA_27: [f64; 27] = [ -0.05257989820636434, -0.27722910598770467, -0.6821639113780065, -1.268814180750757, -2.0391592782504855, -2.9958355818751636, -4.142194482563246, -5.482371716049069, -7.021376024605551, -8.76520271685071, -10.720979045996849, -12.897150901909761, -15.303724197068926, -17.95258016401066, -20.857892743471172, -24.036690385983114, -27.509627633675777, -31.302070792021055, -35.445670666132855, -39.9807226211267, -44.959864785337984, -50.45419615272772, -56.56413090151835, -63.44054668468883, -71.3318480551601, -80.71276384709606, -92.80261352555704]; + 0.05257989820636434, + 0.27722910598770467, + 0.6821639113780065, + 1.268814180750757, + 2.0391592782504855, + 2.9958355818751636, + 4.142194482563246, + 5.482371716049069, + 7.021376024605551, + 8.76520271685071, + 10.720979045996849, + 12.897150901909761, + 15.303724197068926, + 17.95258016401066, + 20.857892743471172, + 24.036690385983114, + 27.509627633675777, + 31.302070792021055, + 35.445670666132855, + 39.9807226211267, + 44.959864785337984, + 50.45419615272772, + 56.56413090151835, + 63.44054668468883, + 71.3318480551601, + 80.71276384709606, + 92.80261352555704, +]; const LAGUERRE_ABSCISSA_28: [f64; 28] = [ -0.05073462484987386, -0.26748726864074074, -0.6581366283547919, -1.223971808384909, -1.9667676124737774, -2.8888833260303217, -3.9933116592501134, -5.283736062843442, -6.764603404243505, -8.441216328271324, -10.31985046299326, -12.407903414460671, -14.71408516413575, -17.248663415608057, -20.023783329951712, -23.053890135030297, -26.35629737440132, -29.95196683359618, -33.86660551658446, -38.13225441019465, -42.78967237077258, -47.89207163362274, -53.5112979596643, -59.74879608464124, -66.75697728390647, -74.78677815233917, -84.31783710722705, -96.58242062752731]; + 0.05073462484987386, + 0.26748726864074074, + 0.6581366283547919, + 1.223971808384909, + 1.9667676124737774, + 2.8888833260303217, + 3.9933116592501134, + 5.283736062843442, + 6.764603404243505, + 8.441216328271324, + 10.31985046299326, + 12.407903414460671, + 14.71408516413575, + 17.248663415608057, + 20.023783329951712, + 23.053890135030297, + 26.35629737440132, + 29.95196683359618, + 33.86660551658446, + 38.13225441019465, + 42.78967237077258, + 47.89207163362274, + 53.5112979596643, + 59.74879608464124, + 66.75697728390647, + 74.78677815233917, + 84.31783710722705, + 96.58242062752731, +]; const LAGUERRE_ABSCISSA_29: [f64; 29] = [ -0.049014489994713764, -0.2584072979187784, -0.6357472158006806, -1.1822010556248432, -1.8993664980026832, -2.789363538356292, -3.8548761581952915, -5.099200088698599, -6.526302885192904, -8.140899733223032, -9.948548893634884, -11.955771944042638, -14.170205843320575, -16.600796552315668, -19.258047913130728, -22.15434543487159, -25.304383763050154, -28.725741025266423, -32.439666742324384, -36.47218971363948, -40.855722336729144, -45.63146770127781, -50.85319151599018, -56.59346289666191, -62.95472850114927, -70.09089459642418, -78.25537041941044, -87.93259364298613, -100.36749160276659]; + 0.049014489994713764, + 0.2584072979187784, + 0.6357472158006806, + 1.1822010556248432, + 1.8993664980026832, + 2.789363538356292, + 3.8548761581952915, + 5.099200088698599, + 6.526302885192904, + 8.140899733223032, + 9.948548893634884, + 11.955771944042638, + 14.170205843320575, + 16.600796552315668, + 19.258047913130728, + 22.15434543487159, + 25.304383763050154, + 28.725741025266423, + 32.439666742324384, + 36.47218971363948, + 40.855722336729144, + 45.63146770127781, + 50.85319151599018, + 56.59346289666191, + 62.95472850114927, + 70.09089459642418, + 78.25537041941044, + 87.93259364298613, + 100.36749160276659, +]; const LAGUERRE_ABSCISSA_30: [f64; 30] = [ -0.04740718054080526, -0.2499239167531594, -0.6148334543927684, -1.1431958256661015, -1.8364545546225723, -2.696521874557216, -3.7258145077795093, -4.927293765849882, -6.304515590965074, -7.86169329337026, -9.603775985479263, -11.53654659795614, -13.666744693064235, -16.002221188981068, -18.55213484014315, -21.327204321783128, -24.340035764532693, -27.60555479678096, -31.141586701111237, -34.96965200824907, -39.11608494906789, -43.61365290848483, -48.5039861638042, -53.841385406507506, -59.6991218592355, -66.18061779443849, -73.44123859555988, -81.73681050672768, -91.55646652253684, -104.15752443105889]; + 0.04740718054080526, + 0.2499239167531594, + 0.6148334543927684, + 1.1431958256661015, + 1.8364545546225723, + 2.696521874557216, + 3.7258145077795093, + 4.927293765849882, + 6.304515590965074, + 7.86169329337026, + 9.603775985479263, + 11.53654659795614, + 13.666744693064235, + 16.002221188981068, + 18.55213484014315, + 21.327204321783128, + 24.340035764532693, + 27.60555479678096, + 31.141586701111237, + 34.96965200824907, + 39.11608494906789, + 43.61365290848483, + 48.5039861638042, + 53.841385406507506, + 59.6991218592355, + 66.18061779443849, + 73.44123859555988, + 81.73681050672768, + 91.55646652253684, + 104.15752443105889, +]; -const LAGUERRE_WEIGHT_1: [f64; 1] = [ -1.0]; -const LAGUERRE_WEIGHT_2: [f64; 2] = [ -0.8535533905932737, -0.14644660940672624]; -const LAGUERRE_WEIGHT_3: [f64; 3] = [ -0.7110930099291729, -0.278517733569241, -0.010389256501586133]; +const LAGUERRE_WEIGHT_1: [f64; 1] = [1.0]; +const LAGUERRE_WEIGHT_2: [f64; 2] = [0.8535533905932737, 0.14644660940672624]; +const LAGUERRE_WEIGHT_3: [f64; 3] = [0.7110930099291729, 0.278517733569241, 0.010389256501586133]; const LAGUERRE_WEIGHT_4: [f64; 4] = [ -0.6031541043416337, -0.35741869243779956, -0.038887908515005405, -0.0005392947055613296]; + 0.6031541043416337, + 0.35741869243779956, + 0.038887908515005405, + 0.0005392947055613296, +]; const LAGUERRE_WEIGHT_5: [f64; 5] = [ -0.5217556105828085, -0.398666811083176, -0.07594244968170769, -0.0036117586799220545, -2.3369972385776248e-05]; + 0.5217556105828085, + 0.398666811083176, + 0.07594244968170769, + 0.0036117586799220545, + 2.3369972385776248e-05, +]; const LAGUERRE_WEIGHT_6: [f64; 6] = [ -0.45896467394996476, -0.41700083077212, -0.11337338207404488, -0.010399197453149087, -0.00026101720281493265, -8.985479064296213e-07]; + 0.45896467394996476, + 0.41700083077212, + 0.11337338207404488, + 0.010399197453149087, + 0.00026101720281493265, + 8.985479064296213e-07, +]; const LAGUERRE_WEIGHT_7: [f64; 7] = [ -0.40931895170127336, -0.4218312778617202, -0.1471263486575053, -0.020633514468716942, -0.001074010143280746, -1.5865464348564196e-05, -3.1703154789955624e-08]; + 0.40931895170127336, + 0.4218312778617202, + 0.1471263486575053, + 0.020633514468716942, + 0.001074010143280746, + 1.5865464348564196e-05, + 3.1703154789955624e-08, +]; const LAGUERRE_WEIGHT_8: [f64; 8] = [ -0.36918858934163495, -0.4187867808143447, -0.17579498663717255, -0.033343492261215794, -0.0027945362352256834, -9.076508773358139e-05, -8.48574671627257e-07, -1.0480011748715153e-09]; + 0.36918858934163495, + 0.4187867808143447, + 0.17579498663717255, + 0.033343492261215794, + 0.0027945362352256834, + 9.076508773358139e-05, + 8.48574671627257e-07, + 1.0480011748715153e-09, +]; const LAGUERRE_WEIGHT_9: [f64; 9] = [ -0.33612642179796287, -0.4112139804239856, -0.1992875253708841, -0.04746056276565138, -0.005599626610794551, -0.00030524976709320943, -6.592123026075329e-06, -4.1107693303495754e-08, -3.290874030350679e-11]; + 0.33612642179796287, + 0.4112139804239856, + 0.1992875253708841, + 0.04746056276565138, + 0.005599626610794551, + 0.00030524976709320943, + 6.592123026075329e-06, + 4.1107693303495754e-08, + 3.290874030350679e-11, +]; const LAGUERRE_WEIGHT_10: [f64; 10] = [ -0.3084411157650173, -0.4011199291552761, -0.2180682876118096, -0.062087456098677773, -0.0095015169751811, -0.0007530083885875384, -2.8259233495995642e-05, -4.249313984962698e-07, -1.839564823979633e-09, -9.91182721960906e-13]; + 0.3084411157650173, + 0.4011199291552761, + 0.2180682876118096, + 0.062087456098677773, + 0.0095015169751811, + 0.0007530083885875384, + 2.8259233495995642e-05, + 4.249313984962698e-07, + 1.839564823979633e-09, + 9.91182721960906e-13, +]; const LAGUERRE_WEIGHT_11: [f64; 11] = [ -0.28493321289419904, -0.38972088952785106, -0.23278183184899082, -0.07656445354619705, -0.014393282767350744, -0.0015188808464848761, -8.513122435471927e-05, -2.2924038795745057e-06, -2.4863537027677806e-08, -7.712626933691416e-11, -2.8837758683235913e-14]; + 0.28493321289419904, + 0.38972088952785106, + 0.23278183184899082, + 0.07656445354619705, + 0.014393282767350744, + 0.0015188808464848761, + 8.513122435471927e-05, + 2.2924038795745057e-06, + 2.4863537027677806e-08, + 7.712626933691416e-11, + 2.8837758683235913e-14, +]; const LAGUERRE_WEIGHT_12: [f64; 12] = [ -0.26473137105543654, -0.3777592758731421, -0.24408201131987906, -0.09044922221168182, -0.020102381154634218, -0.0026639735418653335, -0.0002032315926630013, -8.365055856819926e-06, -1.6684938765409212e-07, -1.342391030515004e-09, -3.0616016350351023e-12, -8.148077467426094e-16]; + 0.26473137105543654, + 0.3777592758731421, + 0.24408201131987906, + 0.09044922221168182, + 0.020102381154634218, + 0.0026639735418653335, + 0.0002032315926630013, + 8.365055856819926e-06, + 1.6684938765409212e-07, + 1.342391030515004e-09, + 3.0616016350351023e-12, + 8.148077467426094e-16, +]; const LAGUERRE_WEIGHT_13: [f64; 13] = [ -0.24718870842995047, -0.36568882290052845, -0.25256242005766244, -0.1034707580241851, -0.02643275441556194, -0.004220396040254825, -0.00041188177047274074, -2.3515473981553592e-05, -7.317311620249228e-07, -1.1088416257040026e-08, -6.770826692205984e-11, -1.159979959905093e-13, -2.2450932038927516e-17]; + 0.24718870842995047, + 0.36568882290052845, + 0.25256242005766244, + 0.1034707580241851, + 0.02643275441556194, + 0.004220396040254825, + 0.00041188177047274074, + 2.3515473981553592e-05, + 7.317311620249228e-07, + 1.1088416257040026e-08, + 6.770826692205984e-11, + 1.159979959905093e-13, + 2.2450932038927516e-17, +]; const LAGUERRE_WEIGHT_14: [f64; 14] = [ -0.23181557714485496, -0.3537846915975482, -0.25873461024543143, -0.11548289355692445, -0.03319209215933767, -0.006192869437006678, -0.0007398903778673914, -5.490719466841746e-05, -2.409585764085411e-06, -5.801543981676581e-08, -6.819314692485005e-10, -3.221207751894856e-12, -4.221352440516672e-15, -6.052375022289209e-19]; + 0.23181557714485496, + 0.3537846915975482, + 0.25873461024543143, + 0.11548289355692445, + 0.03319209215933767, + 0.006192869437006678, + 0.0007398903778673914, + 5.490719466841746e-05, + 2.409585764085411e-06, + 5.801543981676581e-08, + 6.819314692485005e-10, + 3.221207751894856e-12, + 4.221352440516672e-15, + 6.052375022289209e-19, +]; const LAGUERRE_WEIGHT_15: [f64; 15] = [ -0.2182348859400943, -0.34221017792287955, -0.2630275779416778, -0.12642581810592993, -0.04020686492100045, -0.008563877803611772, -0.0012124361472142422, -0.00011167439234425123, -6.459926762022831e-06, -2.2263169070962413e-07, -4.227430384979312e-09, -3.9218972670410663e-11, -1.4565152640730893e-13, -1.4830270511133122e-16, -1.6005949062110965e-20]; + 0.2182348859400943, + 0.34221017792287955, + 0.2630275779416778, + 0.12642581810592993, + 0.04020686492100045, + 0.008563877803611772, + 0.0012124361472142422, + 0.00011167439234425123, + 6.459926762022831e-06, + 2.2263169070962413e-07, + 4.227430384979312e-09, + 3.9218972670410663e-11, + 1.4565152640730893e-13, + 1.4830270511133122e-16, + 1.6005949062110965e-20, +]; const LAGUERRE_WEIGHT_16: [f64; 16] = [ -0.2061517149578049, -0.3310578549508783, -0.2657957776442144, -0.13629693429637874, -0.04732892869412563, -0.011299900080339598, -0.0018490709435263271, -0.0002042719153082809, -1.4844586873981502e-05, -6.828319330871331e-07, -1.8810248410797222e-08, -2.862350242973897e-10, -2.1270790332241214e-12, -6.29796700251788e-15, -5.050473700035608e-18, -4.161462370372851e-22]; + 0.2061517149578049, + 0.3310578549508783, + 0.2657957776442144, + 0.13629693429637874, + 0.04732892869412563, + 0.011299900080339598, + 0.0018490709435263271, + 0.0002042719153082809, + 1.4844586873981502e-05, + 6.828319330871331e-07, + 1.8810248410797222e-08, + 2.862350242973897e-10, + 2.1270790332241214e-12, + 6.29796700251788e-15, + 5.050473700035608e-18, + 4.161462370372851e-22, +]; const LAGUERRE_WEIGHT_17: [f64; 17] = [ -0.195332205251757, -0.3203753572745514, -0.2673297263571719, -0.14512985435876014, -0.05443694324533884, -0.01435729776606191, -0.0026628247355727844, -0.0003436797271563036, -3.027551783782883e-05, -1.768515053231684e-06, -6.576272886810413e-08, -1.4697309321595616e-09, -1.816910362555461e-11, -1.095401388928676e-13, -2.617373882223381e-16, -1.672935693146147e-19, -1.0656263162740864e-23]; + 0.195332205251757, + 0.3203753572745514, + 0.2673297263571719, + 0.14512985435876014, + 0.05443694324533884, + 0.01435729776606191, + 0.0026628247355727844, + 0.0003436797271563036, + 3.027551783782883e-05, + 1.768515053231684e-06, + 6.576272886810413e-08, + 1.4697309321595616e-09, + 1.816910362555461e-11, + 1.095401388928676e-13, + 2.617373882223381e-16, + 1.672935693146147e-19, + 1.0656263162740864e-23, +]; const LAGUERRE_WEIGHT_18: [f64; 18] = [ -0.1855886031469319, -0.3101817663702191, -0.26786656714853346, -0.15297974746807239, -0.06143491786096046, -0.017687213080772597, -0.003660179767759848, -0.0005406227870077252, -5.6169650512141573e-05, -4.0153078837011224e-06, -1.9146698566756363e-07, -5.836095268631481e-09, -1.0717112669553731e-10, -1.089098713888804e-12, -5.3866647483783116e-15, -1.0498659780356833e-17, -5.405398451631025e-21, -2.6916532692009873e-25]; + 0.1855886031469319, + 0.3101817663702191, + 0.26786656714853346, + 0.15297974746807239, + 0.06143491786096046, + 0.017687213080772597, + 0.003660179767759848, + 0.0005406227870077252, + 5.6169650512141573e-05, + 4.0153078837011224e-06, + 1.9146698566756363e-07, + 5.836095268631481e-09, + 1.0717112669553731e-10, + 1.089098713888804e-12, + 5.3866647483783116e-15, + 1.0498659780356833e-17, + 5.405398451631025e-21, + 2.6916532692009873e-25, +]; const LAGUERRE_WEIGHT_19: [f64; 19] = [ -0.17676847491590483, -0.3004781436072563, -0.26759954703817723, -0.1599133721355825, -0.06824937997615013, -0.021239307606544574, -0.004841627351148447, -0.0008049127473813773, -9.652472093153588e-05, -8.20730525805109e-06, -4.830566724730854e-07, -1.9049913611232925e-08, -4.816684630928075e-10, -7.348258839551234e-12, -6.202275387572623e-14, -2.5414308430154715e-16, -4.0788612968257876e-19, -1.7077501875939235e-22, -6.715064649908e-27]; + 0.17676847491590483, + 0.3004781436072563, + 0.26759954703817723, + 0.1599133721355825, + 0.06824937997615013, + 0.021239307606544574, + 0.004841627351148447, + 0.0008049127473813773, + 9.652472093153588e-05, + 8.20730525805109e-06, + 4.830566724730854e-07, + 1.9049913611232925e-08, + 4.816684630928075e-10, + 7.348258839551234e-12, + 6.202275387572623e-14, + 2.5414308430154715e-16, + 4.0788612968257876e-19, + 1.7077501875939235e-22, + 6.715064649908e-27, +]; const LAGUERRE_WEIGHT_20: [f64; 20] = [ -0.1687468018511337, -0.2912543620060606, -0.2666861028669966, -0.16600245326950186, -0.07482606466879074, -0.02496441730928259, -0.0062025508445721095, -0.0011449623864768774, -0.00015574177302780828, -1.5401440865224536e-05, -1.086486366517955e-06, -5.33012090955661e-08, -1.7579811790505475e-09, -3.725502402512163e-11, -4.76752925157805e-13, -3.3728442433624615e-15, -1.1550143395003684e-17, -1.5395221405823035e-20, -5.286442725568928e-24, -1.6564566124990854e-28]; + 0.1687468018511337, + 0.2912543620060606, + 0.2666861028669966, + 0.16600245326950186, + 0.07482606466879074, + 0.02496441730928259, + 0.0062025508445721095, + 0.0011449623864768774, + 0.00015574177302780828, + 1.5401440865224536e-05, + 1.086486366517955e-06, + 5.33012090955661e-08, + 1.7579811790505475e-09, + 3.725502402512163e-11, + 4.76752925157805e-13, + 3.3728442433624615e-15, + 1.1550143395003684e-17, + 1.5395221405823035e-20, + 5.286442725568928e-24, + 1.6564566124990854e-28, +]; const LAGUERRE_WEIGHT_21: [f64; 21] = [ -0.16142010018163386, -0.28249356458300917, -0.2652545755138955, -0.17131939639001792, -0.081126625892352, -0.028816301767768913, -0.0077342394261186035, -0.001567481390421157, -0.00023842265876341067, -2.6930073439685737e-05, -2.2247907936450205e-06, -1.3173344974322964e-07, -5.443952290646455e-09, -1.5163662051980326e-10, -2.7178831180588325e-12, -2.942519354071946e-14, -1.7590740357976582e-16, -5.073802227171899e-19, -5.659720870324164e-22, -1.6062609247991833e-25, -4.0441339271160045e-30]; + 0.16142010018163386, + 0.28249356458300917, + 0.2652545755138955, + 0.17131939639001792, + 0.081126625892352, + 0.028816301767768913, + 0.0077342394261186035, + 0.001567481390421157, + 0.00023842265876341067, + 2.6930073439685737e-05, + 2.2247907936450205e-06, + 1.3173344974322964e-07, + 5.443952290646455e-09, + 1.5163662051980326e-10, + 2.7178831180588325e-12, + 2.942519354071946e-14, + 1.7590740357976582e-16, + 5.073802227171899e-19, + 5.659720870324164e-22, + 1.6062609247991833e-25, + 4.0441339271160045e-30, +]; const LAGUERRE_WEIGHT_22: [f64; 22] = [ -0.15470198763988863, -0.2741750823285574, -0.26340970153563764, -0.17593460926307705, -0.08712562217221223, -0.03275268789653955, -0.009424900256998475, -0.0020773357526546648, -0.00034916737149231, -4.438219314066251e-05, -4.214229901104724e-06, -2.9406682461302104e-07, -1.4761938263897911e-08, -5.186423025724995e-10, -1.2305262515544499e-11, -1.8804655096314958e-13, -1.7355641391268615e-15, -8.831402308327573e-18, -2.1607186468182118e-20, -2.0311199675834204e-23, -4.79790352099101e-27, -9.780246506683717e-32]; + 0.15470198763988863, + 0.2741750823285574, + 0.26340970153563764, + 0.17593460926307705, + 0.08712562217221223, + 0.03275268789653955, + 0.009424900256998475, + 0.0020773357526546648, + 0.00034916737149231, + 4.438219314066251e-05, + 4.214229901104724e-06, + 2.9406682461302104e-07, + 1.4761938263897911e-08, + 5.186423025724995e-10, + 1.2305262515544499e-11, + 1.8804655096314958e-13, + 1.7355641391268615e-15, + 8.831402308327573e-18, + 2.1607186468182118e-20, + 2.0311199675834204e-23, + 4.79790352099101e-27, + 9.780246506683717e-32, +]; const LAGUERRE_WEIGHT_23: [f64; 23] = [ -0.1485197990820251, -0.266276342222034, -0.26123706746535463, -0.1799149140382924, -0.09280788216399254, -0.036735792594760786, -0.011260589222543752, -0.002677540143127065, -0.0004923896728665716, -6.956649894244136e-05, -7.476361523134302e-06, -6.030632412463128e-07, -3.588339690021635e-08, -1.5405512400611729e-09, -4.639077530349208e-11, -9.446912374131525e-13, -1.2397411693143862e-14, -9.82116826801175e-17, -4.281846844983853e-19, -8.943238836296921e-22, -7.129396795318294e-25, -1.4107671088951859e-28, -2.3446147663116474e-33]; + 0.1485197990820251, + 0.266276342222034, + 0.26123706746535463, + 0.1799149140382924, + 0.09280788216399254, + 0.036735792594760786, + 0.011260589222543752, + 0.002677540143127065, + 0.0004923896728665716, + 6.956649894244136e-05, + 7.476361523134302e-06, + 6.030632412463128e-07, + 3.588339690021635e-08, + 1.5405512400611729e-09, + 4.639077530349208e-11, + 9.446912374131525e-13, + 1.2397411693143862e-14, + 9.82116826801175e-17, + 4.281846844983853e-19, + 8.943238836296921e-22, + 7.129396795318294e-25, + 1.4107671088951859e-28, + 2.3446147663116474e-33, +]; const LAGUERRE_WEIGHT_24: [f64; 24] = [ -0.14281197333475043, -0.25877410751744107, -0.2588067072728734, -0.18332268897778237, -0.09816627262992299, -0.04073247815141022, -0.013226019405120549, -0.0033693490584784146, -0.0006721625640935707, -0.00010446121465927847, -1.2544721977993773e-05, -1.151315812737323e-06, -7.960812959133895e-08, -4.072858987550192e-09, -1.507008226292658e-10, -3.917736515058548e-12, -6.894181052958382e-14, -7.819800382459628e-16, -5.350188813010104e-18, -2.0105174645555705e-20, -3.6057658645529064e-23, -2.451818845878714e-26, -4.08830159368094e-30, -5.575345788327942e-35]; + 0.14281197333475043, + 0.25877410751744107, + 0.2588067072728734, + 0.18332268897778237, + 0.09816627262992299, + 0.04073247815141022, + 0.013226019405120549, + 0.0033693490584784146, + 0.0006721625640935707, + 0.00010446121465927847, + 1.2544721977993773e-05, + 1.151315812737323e-06, + 7.960812959133895e-08, + 4.072858987550192e-09, + 1.507008226292658e-10, + 3.917736515058548e-12, + 6.894181052958382e-14, + 7.819800382459628e-16, + 5.350188813010104e-18, + 2.0105174645555705e-20, + 3.6057658645529064e-23, + 2.451818845878714e-26, + 4.08830159368094e-30, + 5.575345788327942e-35, +]; const LAGUERRE_WEIGHT_25: [f64; 25] = [ -0.1375260142293143, -0.2516452737649291, -0.2561760028097598, -0.18621549036244095, -0.10319984810752189, -0.04471416112993464, -0.015305232886395759, -0.004152414632877166, -0.0008920990732597034, -0.00015115601916424346, -2.006553180193332e-05, -2.067774396431917e-06, -1.6346520222911752e-07, -9.76601506212471e-09, -4.327720794185004e-10, -1.3896009633895479e-11, -3.138922792540003e-13, -4.8026148226042224e-15, -4.7358853648073665e-17, -2.8142053798430746e-19, -9.164954395991565e-22, -1.4189400094972862e-24, -8.273651944099231e-28, -1.1688817115426908e-31, -1.3158315000592032e-36]; + 0.1375260142293143, + 0.2516452737649291, + 0.2561760028097598, + 0.18621549036244095, + 0.10319984810752189, + 0.04471416112993464, + 0.015305232886395759, + 0.004152414632877166, + 0.0008920990732597034, + 0.00015115601916424346, + 2.006553180193332e-05, + 2.067774396431917e-06, + 1.6346520222911752e-07, + 9.76601506212471e-09, + 4.327720794185004e-10, + 1.3896009633895479e-11, + 3.138922792540003e-13, + 4.8026148226042224e-15, + 4.7358853648073665e-17, + 2.8142053798430746e-19, + 9.164954395991565e-22, + 1.4189400094972862e-24, + 8.273651944099231e-28, + 1.1688817115426908e-31, + 1.3158315000592032e-36, +]; const LAGUERRE_WEIGHT_26: [f64; 26] = [ -0.13261688414755088, -0.24486736801629908, -0.2533920221271477, -0.18864598364177176, -0.10791234164259454, -0.048656565448924466, -0.017482137978490426, -0.005024983836831609, -0.0011552691607496755, -0.00021179115830037283, -3.079252604171675e-05, -3.52344009102456e-06, -3.1415563253594235e-07, -2.1554568144038427e-08, -1.1204781176705473e-09, -4.3290024051371465e-11, -1.213689159837291e-12, -2.396074223261364e-14, -3.20521855983187e-16, -2.7624941506080987e-18, -1.4330643640727903e-20, -4.064844694113296e-23, -5.459513322799029e-26, -2.7432209871356166e-29, -3.300230478152264e-33, -3.083752269585745e-38]; + 0.13261688414755088, + 0.24486736801629908, + 0.2533920221271477, + 0.18864598364177176, + 0.10791234164259454, + 0.048656565448924466, + 0.017482137978490426, + 0.005024983836831609, + 0.0011552691607496755, + 0.00021179115830037283, + 3.079252604171675e-05, + 3.52344009102456e-06, + 3.1415563253594235e-07, + 2.1554568144038427e-08, + 1.1204781176705473e-09, + 4.3290024051371465e-11, + 1.213689159837291e-12, + 2.396074223261364e-14, + 3.20521855983187e-16, + 2.7624941506080987e-18, + 1.4330643640727903e-20, + 4.064844694113296e-23, + 5.459513322799029e-26, + 2.7432209871356166e-29, + 3.300230478152264e-33, + 3.083752269585745e-38, +]; const LAGUERRE_WEIGHT_27: [f64; 27] = [ -0.12804572690683458, -0.23841884939415778, -0.25049340652299135, -0.19066206759352508, -0.11231094931185093, -0.052539385475131054, -0.01974092327574439, -0.005984113555700946, -0.0014641503609227752, -0.00028849800396584056, -4.5576544403735015e-05, -5.735756119190818e-06, -5.702097017139314e-07, -4.430769157632029e-08, -2.656165316493792e-09, -1.208947524768711e-10, -4.0962644275901e-12, -1.0083497673164991e-13, -1.7490517511153509e-15, -2.0559670832614e-17, -1.5562957367237563e-19, -7.081265177901208e-22, -1.7574720104285717e-24, -2.0570430367976135e-27, -8.94741911536934e-31, -9.209310916917967e-35, -7.179742378294876e-40]; + 0.12804572690683458, + 0.23841884939415778, + 0.25049340652299135, + 0.19066206759352508, + 0.11231094931185093, + 0.052539385475131054, + 0.01974092327574439, + 0.005984113555700946, + 0.0014641503609227752, + 0.00028849800396584056, + 4.5576544403735015e-05, + 5.735756119190818e-06, + 5.702097017139314e-07, + 4.430769157632029e-08, + 2.656165316493792e-09, + 1.208947524768711e-10, + 4.0962644275901e-12, + 1.0083497673164991e-13, + 1.7490517511153509e-15, + 2.0559670832614e-17, + 1.5562957367237563e-19, + 7.081265177901208e-22, + 1.7574720104285717e-24, + 2.0570430367976135e-27, + 8.94741911536934e-31, + 9.209310916917967e-35, + 7.179742378294876e-40, +]; const LAGUERRE_WEIGHT_28: [f64; 28] = [ -0.12377884395428292, -0.23227927690088956, -0.2475118960364775, -0.19230711313239388, -0.11640536172113154, -0.05634590536447879, -0.02206636432625927, -0.00702588763558407, -0.0018206078926958945, -0.0003833443038571334, -6.535087080694586e-05, -8.971362053411014e-06, -9.847012256249517e-07, -8.564075852673259e-08, -5.836838763138484e-09, -3.0756388778423815e-10, -1.2325909527244575e-11, -3.682173674108522e-13, -7.998790575969163e-15, -1.224922500324125e-16, -1.2711242950307056e-18, -8.488593367686924e-21, -3.4024553794256913e-23, -7.420156588867842e-26, -7.600413205801684e-29, -2.8739103179403316e-32, -2.5418229038893288e-36, -1.6613758780291924e-41]; + 0.12377884395428292, + 0.23227927690088956, + 0.2475118960364775, + 0.19230711313239388, + 0.11640536172113154, + 0.05634590536447879, + 0.02206636432625927, + 0.00702588763558407, + 0.0018206078926958945, + 0.0003833443038571334, + 6.535087080694586e-05, + 8.971362053411014e-06, + 9.847012256249517e-07, + 8.564075852673259e-08, + 5.836838763138484e-09, + 3.0756388778423815e-10, + 1.2325909527244575e-11, + 3.682173674108522e-13, + 7.998790575969163e-15, + 1.224922500324125e-16, + 1.2711242950307056e-18, + 8.488593367686924e-21, + 3.4024553794256913e-23, + 7.420156588867842e-26, + 7.600413205801684e-29, + 2.8739103179403316e-32, + 2.5418229038893288e-36, + 1.6613758780291924e-41, +]; const LAGUERRE_WEIGHT_29: [f64; 29] = [ -0.11978686722480197, -0.22642938894472694, -0.2444735653556698, -0.1936202644976424, -0.12020699960179668, -0.06006260605182236, -0.024444040022708252, -0.008145624870286014, -0.002225899096067021, -0.0004982863213445163, -9.111348999272648e-05, -1.3547034631790815e-05, -1.6278500050223739e-06, -1.5687206990177564e-07, -1.2009533101199034e-08, -7.220528067633325e-10, -3.362401315847858e-11, -1.1925479056622084e-12, -3.156204723862708e-14, -6.078331294228565e-16, -8.254298347471583e-18, -7.594039930710283e-20, -4.492421504930552e-22, -1.5926368145878875e-24, -3.064007640463193e-27, -2.75726695359824e-30, -9.099251850437394e-34, -6.943730710008354e-38, -3.8222471284652376e-43]; + 0.11978686722480197, + 0.22642938894472694, + 0.2444735653556698, + 0.1936202644976424, + 0.12020699960179668, + 0.06006260605182236, + 0.024444040022708252, + 0.008145624870286014, + 0.002225899096067021, + 0.0004982863213445163, + 9.111348999272648e-05, + 1.3547034631790815e-05, + 1.6278500050223739e-06, + 1.5687206990177564e-07, + 1.2009533101199034e-08, + 7.220528067633325e-10, + 3.362401315847858e-11, + 1.1925479056622084e-12, + 3.156204723862708e-14, + 6.078331294228565e-16, + 8.254298347471583e-18, + 7.594039930710283e-20, + 4.492421504930552e-22, + 1.5926368145878875e-24, + 3.064007640463193e-27, + 2.75726695359824e-30, + 9.099251850437394e-34, + 6.943730710008354e-38, + 3.8222471284652376e-43, +]; const LAGUERRE_WEIGHT_30: [f64; 30] = [ -0.11604408602043889, -0.22085112475067714, -0.24139982758785372, -0.19463676844641709, -0.12372841596687649, -0.06367878036898661, -0.026860475273379727, -0.009338070881603926, -0.0026806968913368197, -0.0006351291219408556, -0.000123907459906883, -1.982878843895233e-05, -2.5893509291313925e-06, -2.740942840536013e-07, -2.3328311650257382e-08, -1.580745574778328e-09, -8.427479123056716e-11, -3.4851612349078554e-12, -1.0990180597534515e-13, -2.58831266495908e-15, -4.437838059840029e-17, -5.365918308212045e-19, -4.3939468922916045e-21, -2.3114097943885432e-23, -7.274588498292248e-26, -1.2391497014482679e-28, -9.832375083105887e-32, -2.842323553402701e-35, -1.8786080317495154e-39, -8.745980440465012e-45]; \ No newline at end of file + 0.11604408602043889, + 0.22085112475067714, + 0.24139982758785372, + 0.19463676844641709, + 0.12372841596687649, + 0.06367878036898661, + 0.026860475273379727, + 0.009338070881603926, + 0.0026806968913368197, + 0.0006351291219408556, + 0.000123907459906883, + 1.982878843895233e-05, + 2.5893509291313925e-06, + 2.740942840536013e-07, + 2.3328311650257382e-08, + 1.580745574778328e-09, + 8.427479123056716e-11, + 3.4851612349078554e-12, + 1.0990180597534515e-13, + 2.58831266495908e-15, + 4.437838059840029e-17, + 5.365918308212045e-19, + 4.3939468922916045e-21, + 2.3114097943885432e-23, + 7.274588498292248e-26, + 1.2391497014482679e-28, + 9.832375083105887e-32, + 2.842323553402701e-35, + 1.8786080317495154e-39, + 8.745980440465012e-45, +]; diff --git a/src/utils/gh_table.rs b/src/utils/gh_table.rs index a760add..2228857 100644 --- a/src/utils/gh_table.rs +++ b/src/utils/gh_table.rs @@ -2,11 +2,11 @@ use crate::utils::error_codes::GAUSSIAN_QUADRATURE_ORDER_OUT_OF_RANGE; pub const MAX_GH_ORDER: usize = 30; - -pub fn get_gh_weights_and_abscissae(order: usize, index: usize) -> Result<(f64, f64), &'static str> -{ - let ref_abs: f64 = match order - { +pub fn get_gh_weights_and_abscissae( + order: usize, + index: usize, +) -> Result<(f64, f64), &'static str> { + let ref_abs: f64 = match order { 1 => HERMITE_ABSCISSA_1[index], 2 => HERMITE_ABSCISSA_2[index], 3 => HERMITE_ABSCISSA_3[index], @@ -40,8 +40,7 @@ pub fn get_gh_weights_and_abscissae(order: usize, index: usize) -> Result<(f64, _ => return Err(GAUSSIAN_QUADRATURE_ORDER_OUT_OF_RANGE), }; - let ref_weight: f64 = match order - { + let ref_weight: f64 = match order { 1 => HERMITE_WEIGHT_1[index], 2 => HERMITE_WEIGHT_2[index], 3 => HERMITE_WEIGHT_3[index], @@ -81,994 +80,1036 @@ pub fn get_gh_weights_and_abscissae(order: usize, index: usize) -> Result<(f64, // ============================================================================= // Table generated using Python's numpy.polynomial.hermite // ============================================================================= -const HERMITE_ABSCISSA_1: [f64; 1] = [ -0.0]; -const HERMITE_ABSCISSA_2: [f64; 2] = [ --0.7071067811865475, -0.7071067811865475]; -const HERMITE_ABSCISSA_3: [f64; 3] = [ --1.224744871391589, -0.0, -1.224744871391589]; +const HERMITE_ABSCISSA_1: [f64; 1] = [0.0]; +const HERMITE_ABSCISSA_2: [f64; 2] = [-0.7071067811865475, 0.7071067811865475]; +const HERMITE_ABSCISSA_3: [f64; 3] = [-1.224744871391589, 0.0, 1.224744871391589]; const HERMITE_ABSCISSA_4: [f64; 4] = [ --1.6506801238857847, --0.5246476232752904, -0.5246476232752904, -1.6506801238857847]; + -1.6506801238857847, + -0.5246476232752904, + 0.5246476232752904, + 1.6506801238857847, +]; const HERMITE_ABSCISSA_5: [f64; 5] = [ --2.0201828704560856, --0.9585724646138185, -0.0, -0.9585724646138185, -2.0201828704560856]; + -2.0201828704560856, + -0.9585724646138185, + 0.0, + 0.9585724646138185, + 2.0201828704560856, +]; const HERMITE_ABSCISSA_6: [f64; 6] = [ --2.3506049736744923, --1.335849074013697, --0.4360774119276165, -0.4360774119276165, -1.335849074013697, -2.3506049736744923]; + -2.3506049736744923, + -1.335849074013697, + -0.4360774119276165, + 0.4360774119276165, + 1.335849074013697, + 2.3506049736744923, +]; const HERMITE_ABSCISSA_7: [f64; 7] = [ --2.6519613568352334, --1.6735516287674714, --0.8162878828589646, -0.0, -0.8162878828589646, -1.6735516287674714, -2.6519613568352334]; + -2.6519613568352334, + -1.6735516287674714, + -0.8162878828589646, + 0.0, + 0.8162878828589646, + 1.6735516287674714, + 2.6519613568352334, +]; const HERMITE_ABSCISSA_8: [f64; 8] = [ --2.930637420257244, --1.981656756695843, --1.1571937124467802, --0.3811869902073221, -0.3811869902073221, -1.1571937124467802, -1.981656756695843, -2.930637420257244]; + -2.930637420257244, + -1.981656756695843, + -1.1571937124467802, + -0.3811869902073221, + 0.3811869902073221, + 1.1571937124467802, + 1.981656756695843, + 2.930637420257244, +]; const HERMITE_ABSCISSA_9: [f64; 9] = [ --3.1909932017815277, --2.266580584531843, --1.468553289216668, --0.7235510187528376, -0.0, -0.7235510187528376, -1.468553289216668, -2.266580584531843, -3.1909932017815277]; + -3.1909932017815277, + -2.266580584531843, + -1.468553289216668, + -0.7235510187528376, + 0.0, + 0.7235510187528376, + 1.468553289216668, + 2.266580584531843, + 3.1909932017815277, +]; const HERMITE_ABSCISSA_10: [f64; 10] = [ --3.4361591188377374, --2.5327316742327897, --1.7566836492998816, --1.0366108297895136, --0.3429013272237046, -0.3429013272237046, -1.0366108297895136, -1.7566836492998816, -2.5327316742327897, -3.4361591188377374]; + -3.4361591188377374, + -2.5327316742327897, + -1.7566836492998816, + -1.0366108297895136, + -0.3429013272237046, + 0.3429013272237046, + 1.0366108297895136, + 1.7566836492998816, + 2.5327316742327897, + 3.4361591188377374, +]; const HERMITE_ABSCISSA_11: [f64; 11] = [ --3.6684708465595826, --2.7832900997816514, --2.0259480158257555, --1.3265570844949328, --0.6568095668820998, -0.0, -0.6568095668820998, -1.3265570844949328, -2.0259480158257555, -2.7832900997816514, -3.6684708465595826]; + -3.6684708465595826, + -2.7832900997816514, + -2.0259480158257555, + -1.3265570844949328, + -0.6568095668820998, + 0.0, + 0.6568095668820998, + 1.3265570844949328, + 2.0259480158257555, + 2.7832900997816514, + 3.6684708465595826, +]; const HERMITE_ABSCISSA_12: [f64; 12] = [ --3.889724897869782, --3.0206370251208896, --2.2795070805010598, --1.5976826351526048, --0.9477883912401638, --0.31424037625435913, -0.31424037625435913, -0.9477883912401638, -1.5976826351526048, -2.2795070805010598, -3.0206370251208896, -3.889724897869782]; + -3.889724897869782, + -3.0206370251208896, + -2.2795070805010598, + -1.5976826351526048, + -0.9477883912401638, + -0.31424037625435913, + 0.31424037625435913, + 0.9477883912401638, + 1.5976826351526048, + 2.2795070805010598, + 3.0206370251208896, + 3.889724897869782, +]; const HERMITE_ABSCISSA_13: [f64; 13] = [ --4.10133759617864, --3.24660897837241, --2.5197356856782376, --1.853107651601512, --1.2200550365907483, --0.6057638791710601, -0.0, -0.6057638791710601, -1.2200550365907483, -1.853107651601512, -2.5197356856782376, -3.24660897837241, -4.10133759617864]; + -4.10133759617864, + -3.24660897837241, + -2.5197356856782376, + -1.853107651601512, + -1.2200550365907483, + -0.6057638791710601, + 0.0, + 0.6057638791710601, + 1.2200550365907483, + 1.853107651601512, + 2.5197356856782376, + 3.24660897837241, + 4.10133759617864, +]; const HERMITE_ABSCISSA_14: [f64; 14] = [ --4.304448570473632, --3.4626569336022706, --2.7484707249854026, --2.0951832585077166, --1.4766827311411408, --0.8787137873293994, --0.29174551067256205, -0.29174551067256205, -0.8787137873293994, -1.4766827311411408, -2.0951832585077166, -2.7484707249854026, -3.4626569336022706, -4.304448570473632]; + -4.304448570473632, + -3.4626569336022706, + -2.7484707249854026, + -2.0951832585077166, + -1.4766827311411408, + -0.8787137873293994, + -0.29174551067256205, + 0.29174551067256205, + 0.8787137873293994, + 1.4766827311411408, + 2.0951832585077166, + 2.7484707249854026, + 3.4626569336022706, + 4.304448570473632, +]; const HERMITE_ABSCISSA_15: [f64; 15] = [ --4.499990707309392, --3.6699503734044527, --2.967166927905603, --2.325732486173858, --1.7199925751864888, --1.1361155852109206, --0.5650695832555758, -0.0, -0.5650695832555758, -1.1361155852109206, -1.7199925751864888, -2.325732486173858, -2.967166927905603, -3.6699503734044527, -4.499990707309392]; + -4.499990707309392, + -3.6699503734044527, + -2.967166927905603, + -2.325732486173858, + -1.7199925751864888, + -1.1361155852109206, + -0.5650695832555758, + 0.0, + 0.5650695832555758, + 1.1361155852109206, + 1.7199925751864888, + 2.325732486173858, + 2.967166927905603, + 3.6699503734044527, + 4.499990707309392, +]; const HERMITE_ABSCISSA_16: [f64; 16] = [ --4.688738939305819, --3.869447904860123, --3.176999161979956, --2.5462021578474814, --1.9517879909162539, --1.3802585391988809, --0.8229514491446559, --0.27348104613815244, -0.27348104613815244, -0.8229514491446559, -1.3802585391988809, -1.9517879909162539, -2.5462021578474814, -3.176999161979956, -3.869447904860123, -4.688738939305819]; + -4.688738939305819, + -3.869447904860123, + -3.176999161979956, + -2.5462021578474814, + -1.9517879909162539, + -1.3802585391988809, + -0.8229514491446559, + -0.27348104613815244, + 0.27348104613815244, + 0.8229514491446559, + 1.3802585391988809, + 1.9517879909162539, + 2.5462021578474814, + 3.176999161979956, + 3.869447904860123, + 4.688738939305819, +]; const HERMITE_ABSCISSA_17: [f64; 17] = [ --4.871345193674403, --4.0619466758754745, --3.378932091141494, --2.7577629157038888, --2.1735028266666205, --1.6129243142212313, --1.0676487257434506, --0.5316330013426548, -0.0, -0.5316330013426548, -1.0676487257434506, -1.6129243142212313, -2.1735028266666205, -2.7577629157038888, -3.378932091141494, -4.0619466758754745, -4.871345193674403]; + -4.871345193674403, + -4.0619466758754745, + -3.378932091141494, + -2.7577629157038888, + -2.1735028266666205, + -1.6129243142212313, + -1.0676487257434506, + -0.5316330013426548, + 0.0, + 0.5316330013426548, + 1.0676487257434506, + 1.6129243142212313, + 2.1735028266666205, + 2.7577629157038888, + 3.378932091141494, + 4.0619466758754745, + 4.871345193674403, +]; const HERMITE_ABSCISSA_18: [f64; 18] = [ --5.048364008874467, --4.248117873568127, --3.573769068486266, --2.961377505531607, --2.3862990891666858, --1.8355316042616288, --1.3009208583896175, --0.7766829192674116, --0.2582677505190968, -0.2582677505190968, -0.7766829192674116, -1.3009208583896175, -1.8355316042616288, -2.3862990891666858, -2.961377505531607, -3.573769068486266, -4.248117873568127, -5.048364008874467]; + -5.048364008874467, + -4.248117873568127, + -3.573769068486266, + -2.961377505531607, + -2.3862990891666858, + -1.8355316042616288, + -1.3009208583896175, + -0.7766829192674116, + -0.2582677505190968, + 0.2582677505190968, + 0.7766829192674116, + 1.3009208583896175, + 1.8355316042616288, + 2.3862990891666858, + 2.961377505531607, + 3.573769068486266, + 4.248117873568127, + 5.048364008874467, +]; const HERMITE_ABSCISSA_19: [f64; 19] = [ --5.220271690537482, --4.428532806603779, --3.76218735196402, --3.157848818347602, --2.591133789794543, --2.049231709850619, --1.5241706193935332, --1.0103683871343114, --0.5035201634238882, -0.0, -0.5035201634238882, -1.0103683871343114, -1.5241706193935332, -2.049231709850619, -2.591133789794543, -3.157848818347602, -3.76218735196402, -4.428532806603779, -5.220271690537482]; + -5.220271690537482, + -4.428532806603779, + -3.76218735196402, + -3.157848818347602, + -2.591133789794543, + -2.049231709850619, + -1.5241706193935332, + -1.0103683871343114, + -0.5035201634238882, + 0.0, + 0.5035201634238882, + 1.0103683871343114, + 1.5241706193935332, + 2.049231709850619, + 2.591133789794543, + 3.157848818347602, + 3.76218735196402, + 4.428532806603779, + 5.220271690537482, +]; const HERMITE_ABSCISSA_20: [f64; 20] = [ --5.387480890011233, --4.603682449550744, --3.944764040115625, --3.3478545673832163, --2.7888060584281305, --2.2549740020892757, --1.7385377121165861, --1.234076215395323, --0.7374737285453944, --0.24534070830090124, -0.24534070830090124, -0.7374737285453944, -1.234076215395323, -1.7385377121165861, -2.2549740020892757, -2.7888060584281305, -3.3478545673832163, -3.944764040115625, -4.603682449550744, -5.387480890011233]; + -5.387480890011233, + -4.603682449550744, + -3.944764040115625, + -3.3478545673832163, + -2.7888060584281305, + -2.2549740020892757, + -1.7385377121165861, + -1.234076215395323, + -0.7374737285453944, + -0.24534070830090124, + 0.24534070830090124, + 0.7374737285453944, + 1.234076215395323, + 1.7385377121165861, + 2.2549740020892757, + 2.7888060584281305, + 3.3478545673832163, + 3.944764040115625, + 4.603682449550744, + 5.387480890011233, +]; const HERMITE_ABSCISSA_21: [f64; 21] = [ --5.550351873264678, --4.773992343411219, --4.12199554749184, --3.5319728771376777, --2.979991207704598, --2.453552124512838, --1.9449629491862537, --1.448934250650732, --0.961499634418369, --0.47945070707910753, -0.0, -0.47945070707910753, -0.961499634418369, -1.448934250650732, -1.9449629491862537, -2.453552124512838, -2.979991207704598, -3.5319728771376777, -4.12199554749184, -4.773992343411219, -5.550351873264678]; + -5.550351873264678, + -4.773992343411219, + -4.12199554749184, + -3.5319728771376777, + -2.979991207704598, + -2.453552124512838, + -1.9449629491862537, + -1.448934250650732, + -0.961499634418369, + -0.47945070707910753, + 0.0, + 0.47945070707910753, + 0.961499634418369, + 1.448934250650732, + 1.9449629491862537, + 2.453552124512838, + 2.979991207704598, + 3.5319728771376777, + 4.12199554749184, + 4.773992343411219, + 5.550351873264678, +]; const HERMITE_ABSCISSA_22: [f64; 22] = [ --5.7092013532052635, --4.939834131060176, --4.294312480593161, --3.710701532877805, --3.1652659092021374, --2.645637441058173, --2.1442335927985345, --1.6558743732864225, --1.1767139584812445, --0.703686097170007, --0.2341791399309906, -0.2341791399309906, -0.703686097170007, -1.1767139584812445, -1.6558743732864225, -2.1442335927985345, -2.645637441058173, -3.1652659092021374, -3.710701532877805, -4.294312480593161, -4.939834131060176, -5.7092013532052635]; + -5.7092013532052635, + -4.939834131060176, + -4.294312480593161, + -3.710701532877805, + -3.1652659092021374, + -2.645637441058173, + -2.1442335927985345, + -1.6558743732864225, + -1.1767139584812445, + -0.703686097170007, + -0.2341791399309906, + 0.2341791399309906, + 0.703686097170007, + 1.1767139584812445, + 1.6558743732864225, + 2.1442335927985345, + 2.645637441058173, + 3.1652659092021374, + 3.710701532877805, + 4.294312480593161, + 4.939834131060176, + 5.7092013532052635, +]; const HERMITE_ABSCISSA_23: [f64; 23] = [ --5.864309498984572, --5.101534610476677, --4.462091173740006, --3.884472708106102, --3.3451271599412244, --2.831803787126157, --2.337016211474456, --1.855677037671371, --1.3840395856824952, --0.9191514654425638, --0.4585383500681048, -0.0, -0.4585383500681048, -0.9191514654425638, -1.3840395856824952, -1.855677037671371, -2.337016211474456, -2.831803787126157, -3.3451271599412244, -3.884472708106102, -4.462091173740006, -5.101534610476677, -5.864309498984572]; + -5.864309498984572, + -5.101534610476677, + -4.462091173740006, + -3.884472708106102, + -3.3451271599412244, + -2.831803787126157, + -2.337016211474456, + -1.855677037671371, + -1.3840395856824952, + -0.9191514654425638, + -0.4585383500681048, + 0.0, + 0.4585383500681048, + 0.9191514654425638, + 1.3840395856824952, + 1.855677037671371, + 2.337016211474456, + 2.831803787126157, + 3.3451271599412244, + 3.884472708106102, + 4.462091173740006, + 5.101534610476677, + 5.864309498984572, +]; const HERMITE_ABSCISSA_24: [f64; 24] = [ --6.01592556142574, --5.259382927668044, --4.625662756423788, --4.053664402448149, --3.5200068130345246, --3.0125461375655647, --2.523881017011427, --2.049003573661699, --1.5842500109616942, --1.1267608176112451, --0.6741711070372123, --0.22441454747251557, -0.22441454747251557, -0.6741711070372123, -1.1267608176112451, -1.5842500109616942, -2.049003573661699, -2.523881017011427, -3.0125461375655647, -3.5200068130345246, -4.053664402448149, -4.625662756423788, -5.259382927668044, -6.01592556142574]; + -6.01592556142574, + -5.259382927668044, + -4.625662756423788, + -4.053664402448149, + -3.5200068130345246, + -3.0125461375655647, + -2.523881017011427, + -2.049003573661699, + -1.5842500109616942, + -1.1267608176112451, + -0.6741711070372123, + -0.22441454747251557, + 0.22441454747251557, + 0.6741711070372123, + 1.1267608176112451, + 1.5842500109616942, + 2.049003573661699, + 2.523881017011427, + 3.0125461375655647, + 3.5200068130345246, + 4.053664402448149, + 4.625662756423788, + 5.259382927668044, + 6.01592556142574, +]; const HERMITE_ABSCISSA_25: [f64; 25] = [ --6.164272434052452, --5.413636355280033, --4.785320367352224, --4.218609444386561, --3.690282876998356, --3.188294924425105, --2.705320237173026, --2.236420130267281, --1.7780011243371474, --1.327280702073084, --0.8819827562138213, --0.4401472986453083, -0.0, -0.4401472986453083, -0.8819827562138213, -1.327280702073084, -1.7780011243371474, -2.236420130267281, -2.705320237173026, -3.188294924425105, -3.690282876998356, -4.218609444386561, -4.785320367352224, -5.413636355280033, -6.164272434052452]; + -6.164272434052452, + -5.413636355280033, + -4.785320367352224, + -4.218609444386561, + -3.690282876998356, + -3.188294924425105, + -2.705320237173026, + -2.236420130267281, + -1.7780011243371474, + -1.327280702073084, + -0.8819827562138213, + -0.4401472986453083, + 0.0, + 0.4401472986453083, + 0.8819827562138213, + 1.327280702073084, + 1.7780011243371474, + 2.236420130267281, + 2.705320237173026, + 3.188294924425105, + 3.690282876998356, + 4.218609444386561, + 4.785320367352224, + 5.413636355280033, + 6.164272434052452, +]; const HERMITE_ABSCISSA_26: [f64; 26] = [ --6.309550385625694, --5.564524981950103, --4.941324957241379, --4.379602662983305, --3.856288419909149, --3.35942718235083, --2.881762219543087, --2.418415764773779, --1.9658547856411366, --1.5213615166519214, --1.0827330110778832, --0.6480952139934484, --0.2157778562434634, -0.2157778562434634, -0.6480952139934484, -1.0827330110778832, -1.5213615166519214, -1.9658547856411366, -2.418415764773779, -2.881762219543087, -3.35942718235083, -3.856288419909149, -4.379602662983305, -4.941324957241379, -5.564524981950103, -6.309550385625694]; + -6.309550385625694, + -5.564524981950103, + -4.941324957241379, + -4.379602662983305, + -3.856288419909149, + -3.35942718235083, + -2.881762219543087, + -2.418415764773779, + -1.9658547856411366, + -1.5213615166519214, + -1.0827330110778832, + -0.6480952139934484, + -0.2157778562434634, + 0.2157778562434634, + 0.6480952139934484, + 1.0827330110778832, + 1.5213615166519214, + 1.9658547856411366, + 2.418415764773779, + 2.881762219543087, + 3.35942718235083, + 3.856288419909149, + 4.379602662983305, + 4.941324957241379, + 5.564524981950103, + 6.309550385625694, +]; const HERMITE_ABSCISSA_27: [f64; 27] = [ --6.4519401407534716, --5.712255552816536, --5.093910003113184, --4.5369066633724415, --4.018318670408739, --3.526275340134353, --3.053582419822255, --2.5954163389108182, --2.1482966453616275, --1.7095607392603371, --1.277066817339858, --0.849011342060103, --0.42380790054385303, -0.0, -0.42380790054385303, -0.849011342060103, -1.277066817339858, -1.7095607392603371, -2.1482966453616275, -2.5954163389108182, -3.053582419822255, -3.526275340134353, -4.018318670408739, -4.5369066633724415, -5.093910003113184, -5.712255552816536, -6.4519401407534716]; + -6.4519401407534716, + -5.712255552816536, + -5.093910003113184, + -4.5369066633724415, + -4.018318670408739, + -3.526275340134353, + -3.053582419822255, + -2.5954163389108182, + -2.1482966453616275, + -1.7095607392603371, + -1.277066817339858, + -0.849011342060103, + -0.42380790054385303, + 0.0, + 0.42380790054385303, + 0.849011342060103, + 1.277066817339858, + 1.7095607392603371, + 2.1482966453616275, + 2.5954163389108182, + 3.053582419822255, + 3.526275340134353, + 4.018318670408739, + 4.5369066633724415, + 5.093910003113184, + 5.712255552816536, + 6.4519401407534716, +]; const HERMITE_ABSCISSA_28: [f64; 28] = [ --6.591605442367743, --5.85701464138285, --5.243285373202936, --4.690756523943118, --4.1766367421292685, --3.6891342384616794, --3.2211120765614556, --2.767795352913594, --2.3257498426564407, --1.8923604968376853, --1.465537263457409, --1.0435352737542083, --0.6248367195052092, --0.20806738269073688, -0.20806738269073688, -0.6248367195052092, -1.0435352737542083, -1.465537263457409, -1.8923604968376853, -2.3257498426564407, -2.767795352913594, -3.2211120765614556, -3.6891342384616794, -4.1766367421292685, -4.690756523943118, -5.243285373202936, -5.85701464138285, -6.591605442367743]; + -6.591605442367743, + -5.85701464138285, + -5.243285373202936, + -4.690756523943118, + -4.1766367421292685, + -3.6891342384616794, + -3.2211120765614556, + -2.767795352913594, + -2.3257498426564407, + -1.8923604968376853, + -1.465537263457409, + -1.0435352737542083, + -0.6248367195052092, + -0.20806738269073688, + 0.20806738269073688, + 0.6248367195052092, + 1.0435352737542083, + 1.465537263457409, + 1.8923604968376853, + 2.3257498426564407, + 2.767795352913594, + 3.2211120765614556, + 3.6891342384616794, + 4.1766367421292685, + 4.690756523943118, + 5.243285373202936, + 5.85701464138285, + 6.591605442367743, +]; const HERMITE_ABSCISSA_29: [f64; 29] = [ --6.72869519860885, --5.99897128946382, --5.389640521966752, --4.841363651059164, --4.33147829381915, --3.8482667922136202, --3.3846451410922143, --2.9358825042901264, --2.498585691019404, --2.070181076053428, --1.6486229138923163, --1.232215755084753, --0.8194986812709115, --0.4091646363949287, -0.0, -0.4091646363949287, -0.8194986812709115, -1.232215755084753, -1.6486229138923163, -2.070181076053428, -2.498585691019404, -2.9358825042901264, -3.3846451410922143, -3.8482667922136202, -4.33147829381915, -4.841363651059164, -5.389640521966752, -5.99897128946382, -6.72869519860885]; + -6.72869519860885, + -5.99897128946382, + -5.389640521966752, + -4.841363651059164, + -4.33147829381915, + -3.8482667922136202, + -3.3846451410922143, + -2.9358825042901264, + -2.498585691019404, + -2.070181076053428, + -1.6486229138923163, + -1.232215755084753, + -0.8194986812709115, + -0.4091646363949287, + 0.0, + 0.4091646363949287, + 0.8194986812709115, + 1.232215755084753, + 1.6486229138923163, + 2.070181076053428, + 2.498585691019404, + 2.9358825042901264, + 3.3846451410922143, + 3.8482667922136202, + 4.33147829381915, + 4.841363651059164, + 5.389640521966752, + 5.99897128946382, + 6.72869519860885, +]; const HERMITE_ABSCISSA_30: [f64; 30] = [ --6.863345293529892, --6.138279220123935, --5.533147151567496, --4.988918968589944, --4.4830553570925185, --4.003908603861229, --3.54444387315535, --3.0999705295864417, --2.6671321245356174, --2.243391467761504, --1.826741143603688, --1.4155278001981886, --1.0083382710467235, --0.6039210586255523, --0.2011285765488715, -0.2011285765488715, -0.6039210586255523, -1.0083382710467235, -1.4155278001981886, -1.826741143603688, -2.243391467761504, -2.6671321245356174, -3.0999705295864417, -3.54444387315535, -4.003908603861229, -4.4830553570925185, -4.988918968589944, -5.533147151567496, -6.138279220123935, -6.863345293529892]; + -6.863345293529892, + -6.138279220123935, + -5.533147151567496, + -4.988918968589944, + -4.4830553570925185, + -4.003908603861229, + -3.54444387315535, + -3.0999705295864417, + -2.6671321245356174, + -2.243391467761504, + -1.826741143603688, + -1.4155278001981886, + -1.0083382710467235, + -0.6039210586255523, + -0.2011285765488715, + 0.2011285765488715, + 0.6039210586255523, + 1.0083382710467235, + 1.4155278001981886, + 1.826741143603688, + 2.243391467761504, + 2.6671321245356174, + 3.0999705295864417, + 3.54444387315535, + 4.003908603861229, + 4.4830553570925185, + 4.988918968589944, + 5.533147151567496, + 6.138279220123935, + 6.863345293529892, +]; -const HERMITE_WEIGHT_1: [f64; 1] = [ -1.7724538509055159]; -const HERMITE_WEIGHT_2: [f64; 2] = [ -0.8862269254527579, -0.8862269254527579]; -const HERMITE_WEIGHT_3: [f64; 3] = [ -0.2954089751509194, -1.1816359006036772, -0.2954089751509194]; +const HERMITE_WEIGHT_1: [f64; 1] = [1.7724538509055159]; +const HERMITE_WEIGHT_2: [f64; 2] = [0.8862269254527579, 0.8862269254527579]; +const HERMITE_WEIGHT_3: [f64; 3] = [0.2954089751509194, 1.1816359006036772, 0.2954089751509194]; const HERMITE_WEIGHT_4: [f64; 4] = [ -0.08131283544724519, -0.8049140900055127, -0.8049140900055127, -0.08131283544724519]; + 0.08131283544724519, + 0.8049140900055127, + 0.8049140900055127, + 0.08131283544724519, +]; const HERMITE_WEIGHT_5: [f64; 5] = [ -0.019953242059045917, -0.3936193231522411, -0.9453087204829418, -0.3936193231522411, -0.019953242059045917]; + 0.019953242059045917, + 0.3936193231522411, + 0.9453087204829418, + 0.3936193231522411, + 0.019953242059045917, +]; const HERMITE_WEIGHT_6: [f64; 6] = [ -0.004530009905508835, -0.15706732032285647, -0.7246295952243924, -0.7246295952243924, -0.15706732032285647, -0.004530009905508835]; + 0.004530009905508835, + 0.15706732032285647, + 0.7246295952243924, + 0.7246295952243924, + 0.15706732032285647, + 0.004530009905508835, +]; const HERMITE_WEIGHT_7: [f64; 7] = [ -0.0009717812450995199, -0.05451558281912705, -0.4256072526101278, -0.8102646175568072, -0.4256072526101278, -0.05451558281912705, -0.0009717812450995199]; + 0.0009717812450995199, + 0.05451558281912705, + 0.4256072526101278, + 0.8102646175568072, + 0.4256072526101278, + 0.05451558281912705, + 0.0009717812450995199, +]; const HERMITE_WEIGHT_8: [f64; 8] = [ -0.00019960407221136783, -0.017077983007413467, -0.20780232581489183, -0.6611470125582415, -0.6611470125582415, -0.20780232581489183, -0.017077983007413467, -0.00019960407221136783]; + 0.00019960407221136783, + 0.017077983007413467, + 0.20780232581489183, + 0.6611470125582415, + 0.6611470125582415, + 0.20780232581489183, + 0.017077983007413467, + 0.00019960407221136783, +]; const HERMITE_WEIGHT_9: [f64; 9] = [ -3.9606977263264365e-05, -0.004943624275536941, -0.08847452739437664, -0.43265155900255564, -0.720235215606051, -0.43265155900255564, -0.08847452739437664, -0.004943624275536941, -3.9606977263264365e-05]; + 3.9606977263264365e-05, + 0.004943624275536941, + 0.08847452739437664, + 0.43265155900255564, + 0.720235215606051, + 0.43265155900255564, + 0.08847452739437664, + 0.004943624275536941, + 3.9606977263264365e-05, +]; const HERMITE_WEIGHT_10: [f64; 10] = [ -7.640432855232641e-06, -0.0013436457467812324, -0.033874394455481106, -0.2401386110823147, -0.6108626337353258, -0.6108626337353258, -0.2401386110823147, -0.033874394455481106, -0.0013436457467812324, -7.640432855232641e-06]; + 7.640432855232641e-06, + 0.0013436457467812324, + 0.033874394455481106, + 0.2401386110823147, + 0.6108626337353258, + 0.6108626337353258, + 0.2401386110823147, + 0.033874394455481106, + 0.0013436457467812324, + 7.640432855232641e-06, +]; const HERMITE_WEIGHT_11: [f64; 11] = [ -1.4395603937142596e-06, -0.00034681946632334544, -0.011911395444911507, -0.11722787516770851, -0.42935975235612495, -0.6547592869145916, -0.42935975235612495, -0.11722787516770851, -0.011911395444911507, -0.00034681946632334544, -1.4395603937142596e-06]; + 1.4395603937142596e-06, + 0.00034681946632334544, + 0.011911395444911507, + 0.11722787516770851, + 0.42935975235612495, + 0.6547592869145916, + 0.42935975235612495, + 0.11722787516770851, + 0.011911395444911507, + 0.00034681946632334544, + 1.4395603937142596e-06, +]; const HERMITE_WEIGHT_12: [f64; 12] = [ -2.6585516843563044e-07, -8.573687043587868e-05, -0.00390539058462906, -0.05160798561588398, -0.2604923102641611, -0.5701352362624795, -0.5701352362624795, -0.2604923102641611, -0.05160798561588398, -0.00390539058462906, -8.573687043587868e-05, -2.6585516843563044e-07]; + 2.6585516843563044e-07, + 8.573687043587868e-05, + 0.00390539058462906, + 0.05160798561588398, + 0.2604923102641611, + 0.5701352362624795, + 0.5701352362624795, + 0.2604923102641611, + 0.05160798561588398, + 0.00390539058462906, + 8.573687043587868e-05, + 2.6585516843563044e-07, +]; const HERMITE_WEIGHT_13: [f64; 13] = [ -4.825731850073125e-08, -2.0430360402707087e-05, -0.001207459992719386, -0.020862775296169953, -0.1403233206870235, -0.4216162968985432, -0.6043931879211613, -0.4216162968985432, -0.1403233206870235, -0.020862775296169953, -0.001207459992719386, -2.0430360402707087e-05, -4.825731850073125e-08]; + 4.825731850073125e-08, + 2.0430360402707087e-05, + 0.001207459992719386, + 0.020862775296169953, + 0.1403233206870235, + 0.4216162968985432, + 0.6043931879211613, + 0.4216162968985432, + 0.1403233206870235, + 0.020862775296169953, + 0.001207459992719386, + 2.0430360402707087e-05, + 4.825731850073125e-08, +]; const HERMITE_WEIGHT_14: [f64; 14] = [ -8.628591168125132e-09, -4.71648435501891e-06, -0.00035509261355192297, -0.007850054726457945, -0.06850553422346528, -0.2731056090642464, -0.5364059097120901, -0.5364059097120901, -0.2731056090642464, -0.06850553422346528, -0.007850054726457945, -0.00035509261355192297, -4.71648435501891e-06, -8.628591168125132e-09]; + 8.628591168125132e-09, + 4.71648435501891e-06, + 0.00035509261355192297, + 0.007850054726457945, + 0.06850553422346528, + 0.2731056090642464, + 0.5364059097120901, + 0.5364059097120901, + 0.2731056090642464, + 0.06850553422346528, + 0.007850054726457945, + 0.00035509261355192297, + 4.71648435501891e-06, + 8.628591168125132e-09, +]; const HERMITE_WEIGHT_15: [f64; 15] = [ -1.522475804253521e-09, -1.0591155477110625e-06, -0.00010000444123249982, -0.002778068842912775, -0.0307800338725461, -0.15848891579593571, -0.4120286874988987, -0.5641003087264174, -0.4120286874988987, -0.15848891579593571, -0.0307800338725461, -0.002778068842912775, -0.00010000444123249982, -1.0591155477110625e-06, -1.522475804253521e-09]; + 1.522475804253521e-09, + 1.0591155477110625e-06, + 0.00010000444123249982, + 0.002778068842912775, + 0.0307800338725461, + 0.15848891579593571, + 0.4120286874988987, + 0.5641003087264174, + 0.4120286874988987, + 0.15848891579593571, + 0.0307800338725461, + 0.002778068842912775, + 0.00010000444123249982, + 1.0591155477110625e-06, + 1.522475804253521e-09, +]; const HERMITE_WEIGHT_16: [f64; 16] = [ -2.6548074740111673e-10, -2.3209808448652032e-07, -2.7118600925378892e-05, -0.0009322840086241807, -0.012880311535509989, -0.08381004139898583, -0.2806474585285337, -0.5079294790166137, -0.5079294790166137, -0.2806474585285337, -0.08381004139898583, -0.012880311535509989, -0.0009322840086241807, -2.7118600925378892e-05, -2.3209808448652032e-07, -2.6548074740111673e-10]; + 2.6548074740111673e-10, + 2.3209808448652032e-07, + 2.7118600925378892e-05, + 0.0009322840086241807, + 0.012880311535509989, + 0.08381004139898583, + 0.2806474585285337, + 0.5079294790166137, + 0.5079294790166137, + 0.2806474585285337, + 0.08381004139898583, + 0.012880311535509989, + 0.0009322840086241807, + 2.7118600925378892e-05, + 2.3209808448652032e-07, + 2.6548074740111673e-10, +]; const HERMITE_WEIGHT_17: [f64; 17] = [ -4.5805789307986096e-11, -4.97707898163077e-08, -7.112289140021293e-06, -0.0002986432866977531, -0.005067349957627545, -0.04092003414975629, -0.17264829767009698, -0.40182646947041206, -0.5309179376248635, -0.40182646947041206, -0.17264829767009698, -0.04092003414975629, -0.005067349957627545, -0.0002986432866977531, -7.112289140021293e-06, -4.97707898163077e-08, -4.5805789307986096e-11]; + 4.5805789307986096e-11, + 4.97707898163077e-08, + 7.112289140021293e-06, + 0.0002986432866977531, + 0.005067349957627545, + 0.04092003414975629, + 0.17264829767009698, + 0.40182646947041206, + 0.5309179376248635, + 0.40182646947041206, + 0.17264829767009698, + 0.04092003414975629, + 0.005067349957627545, + 0.0002986432866977531, + 7.112289140021293e-06, + 4.97707898163077e-08, + 4.5805789307986096e-11, +]; const HERMITE_WEIGHT_18: [f64; 18] = [ -7.828199772115908e-12, -1.0467205795792089e-08, -1.810654481093432e-06, -9.18112686792939e-05, -0.001888522630268417, -0.018640042387544676, -0.09730174764131541, -0.2848072856699793, -0.48349569472545567, -0.48349569472545567, -0.2848072856699793, -0.09730174764131541, -0.018640042387544676, -0.001888522630268417, -9.18112686792939e-05, -1.810654481093432e-06, -1.0467205795792089e-08, -7.828199772115908e-12]; + 7.828199772115908e-12, + 1.0467205795792089e-08, + 1.810654481093432e-06, + 9.18112686792939e-05, + 0.001888522630268417, + 0.018640042387544676, + 0.09730174764131541, + 0.2848072856699793, + 0.48349569472545567, + 0.48349569472545567, + 0.2848072856699793, + 0.09730174764131541, + 0.018640042387544676, + 0.001888522630268417, + 9.18112686792939e-05, + 1.810654481093432e-06, + 1.0467205795792089e-08, + 7.828199772115908e-12, +]; const HERMITE_WEIGHT_19: [f64; 19] = [ -1.3262970944985234e-12, -2.163051009863575e-09, -4.488243147223115e-07, -2.7209197763161712e-05, -0.0006708775214071804, -0.007988866777723026, -0.050810386909052006, -0.1836327013069971, -0.3916089886130303, -0.5029748882761865, -0.3916089886130303, -0.1836327013069971, -0.050810386909052006, -0.007988866777723026, -0.0006708775214071804, -2.7209197763161712e-05, -4.488243147223115e-07, -2.163051009863575e-09, -1.3262970944985234e-12]; + 1.3262970944985234e-12, + 2.163051009863575e-09, + 4.488243147223115e-07, + 2.7209197763161712e-05, + 0.0006708775214071804, + 0.007988866777723026, + 0.050810386909052006, + 0.1836327013069971, + 0.3916089886130303, + 0.5029748882761865, + 0.3916089886130303, + 0.1836327013069971, + 0.050810386909052006, + 0.007988866777723026, + 0.0006708775214071804, + 2.7209197763161712e-05, + 4.488243147223115e-07, + 2.163051009863575e-09, + 1.3262970944985234e-12, +]; const HERMITE_WEIGHT_20: [f64; 20] = [ -2.2293936455341447e-13, -4.3993409922731747e-10, -1.0860693707692782e-07, -7.80255647853206e-06, -0.00022833863601635365, -0.0032437733422378567, -0.024810520887463643, -0.1090172060200233, -0.28667550536283415, -0.4622436696006101, -0.4622436696006101, -0.28667550536283415, -0.1090172060200233, -0.024810520887463643, -0.0032437733422378567, -0.00022833863601635365, -7.80255647853206e-06, -1.0860693707692782e-07, -4.3993409922731747e-10, -2.2293936455341447e-13]; + 2.2293936455341447e-13, + 4.3993409922731747e-10, + 1.0860693707692782e-07, + 7.80255647853206e-06, + 0.00022833863601635365, + 0.0032437733422378567, + 0.024810520887463643, + 0.1090172060200233, + 0.28667550536283415, + 0.4622436696006101, + 0.4622436696006101, + 0.28667550536283415, + 0.1090172060200233, + 0.024810520887463643, + 0.0032437733422378567, + 0.00022833863601635365, + 7.80255647853206e-06, + 1.0860693707692782e-07, + 4.3993409922731747e-10, + 2.2293936455341447e-13, +]; const HERMITE_WEIGHT_21: [f64; 21] = [ -3.720365070136023e-14, -8.818611242049933e-11, -2.5712301800593154e-08, -2.17188489805667e-06, -7.478398867310063e-05, -0.0012549820417264088, -0.011414065837434397, -0.0601796466589123, -0.19212032406699775, -0.3816690736135022, -0.47902370312017756, -0.3816690736135022, -0.19212032406699775, -0.0601796466589123, -0.011414065837434397, -0.0012549820417264088, -7.478398867310063e-05, -2.17188489805667e-06, -2.5712301800593154e-08, -8.818611242049933e-11, -3.720365070136023e-14]; + 3.720365070136023e-14, + 8.818611242049933e-11, + 2.5712301800593154e-08, + 2.17188489805667e-06, + 7.478398867310063e-05, + 0.0012549820417264088, + 0.011414065837434397, + 0.0601796466589123, + 0.19212032406699775, + 0.3816690736135022, + 0.47902370312017756, + 0.3816690736135022, + 0.19212032406699775, + 0.0601796466589123, + 0.011414065837434397, + 0.0012549820417264088, + 7.478398867310063e-05, + 2.17188489805667e-06, + 2.5712301800593154e-08, + 8.818611242049933e-11, + 3.720365070136023e-14, +]; const HERMITE_WEIGHT_22: [f64; 22] = [ -6.167183424404064e-15, -1.744339007547978e-11, -5.966990986059659e-09, -5.884287563301018e-07, -2.36551285525104e-05, -0.0004648850508842517, -0.004978399335051638, -0.03114037088442385, -0.11910236095878239, -0.2869714332469073, -0.44354522643495903, -0.44354522643495903, -0.2869714332469073, -0.11910236095878239, -0.03114037088442385, -0.004978399335051638, -0.0004648850508842517, -2.36551285525104e-05, -5.884287563301018e-07, -5.966990986059659e-09, -1.744339007547978e-11, -6.167183424404064e-15]; + 6.167183424404064e-15, + 1.744339007547978e-11, + 5.966990986059659e-09, + 5.884287563301018e-07, + 2.36551285525104e-05, + 0.0004648850508842517, + 0.004978399335051638, + 0.03114037088442385, + 0.11910236095878239, + 0.2869714332469073, + 0.44354522643495903, + 0.44354522643495903, + 0.2869714332469073, + 0.11910236095878239, + 0.03114037088442385, + 0.004978399335051638, + 0.0004648850508842517, + 2.36551285525104e-05, + 5.884287563301018e-07, + 5.966990986059659e-09, + 1.744339007547978e-11, + 6.167183424404064e-15, +]; const HERMITE_WEIGHT_23: [f64; 23] = [ -1.0160384620636804e-15, -3.40831409803052e-12, -1.3596296504028966e-09, -1.555339329145767e-07, -7.249295918002263e-06, -0.00016556169914187427, -0.002069567874960639, -0.01520708400448414, -0.06889028942908743, -0.19864489857802245, -0.372143824877565, -0.4581965855932132, -0.372143824877565, -0.19864489857802245, -0.06889028942908743, -0.01520708400448414, -0.002069567874960639, -0.00016556169914187427, -7.249295918002263e-06, -1.555339329145767e-07, -1.3596296504028966e-09, -3.40831409803052e-12, -1.0160384620636804e-15]; + 1.0160384620636804e-15, + 3.40831409803052e-12, + 1.3596296504028966e-09, + 1.555339329145767e-07, + 7.249295918002263e-06, + 0.00016556169914187427, + 0.002069567874960639, + 0.01520708400448414, + 0.06889028942908743, + 0.19864489857802245, + 0.372143824877565, + 0.4581965855932132, + 0.372143824877565, + 0.19864489857802245, + 0.06889028942908743, + 0.01520708400448414, + 0.002069567874960639, + 0.00016556169914187427, + 7.249295918002263e-06, + 1.555339329145767e-07, + 1.3596296504028966e-09, + 3.40831409803052e-12, + 1.0160384620636804e-15, +]; const HERMITE_WEIGHT_24: [f64; 24] = [ -1.6643684964891008e-16, -6.584620243078167e-13, -3.0462542699875555e-10, -4.018971174941438e-08, -2.1582457049023414e-06, -5.688691636404392e-05, -0.0008236924826884169, -0.007048355810072673, -0.037445470503230736, -0.12773962178455917, -0.2861795353464429, -0.42693116386869934, -0.42693116386869934, -0.2861795353464429, -0.12773962178455917, -0.037445470503230736, -0.007048355810072673, -0.0008236924826884169, -5.688691636404392e-05, -2.1582457049023414e-06, -4.018971174941438e-08, -3.0462542699875555e-10, -6.584620243078167e-13, -1.6643684964891008e-16]; + 1.6643684964891008e-16, + 6.584620243078167e-13, + 3.0462542699875555e-10, + 4.018971174941438e-08, + 2.1582457049023414e-06, + 5.688691636404392e-05, + 0.0008236924826884169, + 0.007048355810072673, + 0.037445470503230736, + 0.12773962178455917, + 0.2861795353464429, + 0.42693116386869934, + 0.42693116386869934, + 0.2861795353464429, + 0.12773962178455917, + 0.037445470503230736, + 0.007048355810072673, + 0.0008236924826884169, + 5.688691636404392e-05, + 2.1582457049023414e-06, + 4.018971174941438e-08, + 3.0462542699875555e-10, + 6.584620243078167e-13, + 1.6643684964891008e-16, +]; const HERMITE_WEIGHT_25: [f64; 25] = [ -2.7119235140383954e-17, -1.258814987746549e-13, -6.719638417706253e-11, -1.017038250301848e-08, -6.257032499691108e-07, -1.8915972957340455e-05, -0.00031508363874548415, -0.00311570872012563, -0.019243098965408895, -0.07688899517580887, -0.20362113667812404, -0.36308898927589045, -0.43986872216948497, -0.36308898927589045, -0.20362113667812404, -0.07688899517580887, -0.019243098965408895, -0.00311570872012563, -0.00031508363874548415, -1.8915972957340455e-05, -6.257032499691108e-07, -1.017038250301848e-08, -6.719638417706253e-11, -1.258814987746549e-13, -2.7119235140383954e-17]; + 2.7119235140383954e-17, + 1.258814987746549e-13, + 6.719638417706253e-11, + 1.017038250301848e-08, + 6.257032499691108e-07, + 1.8915972957340455e-05, + 0.00031508363874548415, + 0.00311570872012563, + 0.019243098965408895, + 0.07688899517580887, + 0.20362113667812404, + 0.36308898927589045, + 0.43986872216948497, + 0.36308898927589045, + 0.20362113667812404, + 0.07688899517580887, + 0.019243098965408895, + 0.00311570872012563, + 0.00031508363874548415, + 1.8915972957340455e-05, + 6.257032499691108e-07, + 1.017038250301848e-08, + 6.719638417706253e-11, + 1.258814987746549e-13, + 2.7119235140383954e-17, +]; const HERMITE_WEIGHT_26: [f64; 26] = [ -4.396916094753858e-18, -2.3831486593721533e-14, -1.4609999339815978e-11, -2.5244940344905305e-09, -1.7701063373973586e-07, -6.103291717395996e-06, -0.00011622970160310945, -0.0013190647223238565, -0.009397901291159578, -0.0435982272172508, -0.13511332791178782, -0.2846322411767845, -0.41204365059036924, -0.41204365059036924, -0.2846322411767845, -0.13511332791178782, -0.0435982272172508, -0.009397901291159578, -0.0013190647223238565, -0.00011622970160310945, -6.103291717395996e-06, -1.7701063373973586e-07, -2.5244940344905305e-09, -1.4609999339815978e-11, -2.3831486593721533e-14, -4.396916094753858e-18]; + 4.396916094753858e-18, + 2.3831486593721533e-14, + 1.4609999339815978e-11, + 2.5244940344905305e-09, + 1.7701063373973586e-07, + 6.103291717395996e-06, + 0.00011622970160310945, + 0.0013190647223238565, + 0.009397901291159578, + 0.0435982272172508, + 0.13511332791178782, + 0.2846322411767845, + 0.41204365059036924, + 0.41204365059036924, + 0.2846322411767845, + 0.13511332791178782, + 0.0435982272172508, + 0.009397901291159578, + 0.0013190647223238565, + 0.00011622970160310945, + 6.103291717395996e-06, + 1.7701063373973586e-07, + 2.5244940344905305e-09, + 1.4609999339815978e-11, + 2.3831486593721533e-14, + 4.396916094753858e-18, +]; const HERMITE_WEIGHT_27: [f64; 27] = [ -7.095779297051429e-19, -4.4707724573931376e-15, -3.1341176136230647e-12, -6.155031578231804e-10, -4.895400409699535e-08, -1.9152809005952912e-06, -4.1467580043841464e-05, -0.0005367696156881122, -0.004381279835792532, -0.023415933625341938, -0.08417308108405192, -0.20737048075100944, -0.35451730409975385, -0.42357728801505956, -0.35451730409975385, -0.20737048075100944, -0.08417308108405192, -0.023415933625341938, -0.004381279835792532, -0.0005367696156881122, -4.1467580043841464e-05, -1.9152809005952912e-06, -4.895400409699535e-08, -6.155031578231804e-10, -3.1341176136230647e-12, -4.4707724573931376e-15, -7.095779297051429e-19]; + 7.095779297051429e-19, + 4.4707724573931376e-15, + 3.1341176136230647e-12, + 6.155031578231804e-10, + 4.895400409699535e-08, + 1.9152809005952912e-06, + 4.1467580043841464e-05, + 0.0005367696156881122, + 0.004381279835792532, + 0.023415933625341938, + 0.08417308108405192, + 0.20737048075100944, + 0.35451730409975385, + 0.42357728801505956, + 0.35451730409975385, + 0.20737048075100944, + 0.08417308108405192, + 0.023415933625341938, + 0.004381279835792532, + 0.0005367696156881122, + 4.1467580043841464e-05, + 1.9152809005952912e-06, + 4.895400409699535e-08, + 6.155031578231804e-10, + 3.1341176136230647e-12, + 4.4707724573931376e-15, + 7.095779297051429e-19, +]; const HERMITE_WEIGHT_28: [f64; 28] = [ -1.1401393479036659e-19, -8.315937951206773e-16, -6.639436714909621e-13, -1.4758531682776932e-10, -1.3256825015417047e-08, -5.857719720992982e-07, -1.4345504229714393e-05, -0.0002106181000240319, -0.0019573312944089908, -0.01196842321435482, -0.04951488928989816, -0.1413946097869548, -0.28256139125938884, -0.39860471782645124, -0.39860471782645124, -0.28256139125938884, -0.1413946097869548, -0.04951488928989816, -0.01196842321435482, -0.0019573312944089908, -0.0002106181000240319, -1.4345504229714393e-05, -5.857719720992982e-07, -1.3256825015417047e-08, -1.4758531682776932e-10, -6.639436714909621e-13, -8.315937951206773e-16, -1.1401393479036659e-19]; + 1.1401393479036659e-19, + 8.315937951206773e-16, + 6.639436714909621e-13, + 1.4758531682776932e-10, + 1.3256825015417047e-08, + 5.857719720992982e-07, + 1.4345504229714393e-05, + 0.0002106181000240319, + 0.0019573312944089908, + 0.01196842321435482, + 0.04951488928989816, + 0.1413946097869548, + 0.28256139125938884, + 0.39860471782645124, + 0.39860471782645124, + 0.28256139125938884, + 0.1413946097869548, + 0.04951488928989816, + 0.01196842321435482, + 0.0019573312944089908, + 0.0002106181000240319, + 1.4345504229714393e-05, + 5.857719720992982e-07, + 1.3256825015417047e-08, + 1.4758531682776932e-10, + 6.639436714909621e-13, + 8.315937951206773e-16, + 1.1401393479036659e-19, +]; const HERMITE_WEIGHT_29: [f64; 29] = [ -1.8244608527672462e-20, -1.53450044460532e-16, -1.3901072714495982e-13, -3.4841301613084254e-11, -3.5203123276007064e-09, -1.749229129949943e-07, -4.823073497647774e-06, -7.990920354521803e-05, -0.000840792506140262, -0.005845503545271507, -0.02763965559202372, -0.0907688422155782, -0.2101426944492106, -0.34641893907167015, -0.40897117463522964, -0.34641893907167015, -0.2101426944492106, -0.0907688422155782, -0.02763965559202372, -0.005845503545271507, -0.000840792506140262, -7.990920354521803e-05, -4.823073497647774e-06, -1.749229129949943e-07, -3.5203123276007064e-09, -3.4841301613084254e-11, -1.3901072714495982e-13, -1.53450044460532e-16, -1.8244608527672462e-20]; + 1.8244608527672462e-20, + 1.53450044460532e-16, + 1.3901072714495982e-13, + 3.4841301613084254e-11, + 3.5203123276007064e-09, + 1.749229129949943e-07, + 4.823073497647774e-06, + 7.990920354521803e-05, + 0.000840792506140262, + 0.005845503545271507, + 0.02763965559202372, + 0.0907688422155782, + 0.2101426944492106, + 0.34641893907167015, + 0.40897117463522964, + 0.34641893907167015, + 0.2101426944492106, + 0.0907688422155782, + 0.02763965559202372, + 0.005845503545271507, + 0.000840792506140262, + 7.990920354521803e-05, + 4.823073497647774e-06, + 1.749229129949943e-07, + 3.5203123276007064e-09, + 3.4841301613084254e-11, + 1.3901072714495982e-13, + 1.53450044460532e-16, + 1.8244608527672462e-20, +]; const HERMITE_WEIGHT_30: [f64; 30] = [ -2.9082547001312045e-21, -2.810333602750875e-17, -2.8786070805487023e-14, -8.106186297463033e-12, -9.178580424378485e-10, -5.108522450775958e-08, -1.579094887324711e-06, -2.938725228922988e-05, -0.00034831012431868485, -0.0027379224730676565, -0.014703829704826678, -0.055144176870234186, -0.14673584754089003, -0.28013093083921264, -0.38639488954181395, -0.38639488954181395, -0.28013093083921264, -0.14673584754089003, -0.055144176870234186, -0.014703829704826678, -0.0027379224730676565, -0.00034831012431868485, -2.938725228922988e-05, -1.579094887324711e-06, -5.108522450775958e-08, -9.178580424378485e-10, -8.106186297463033e-12, -2.8786070805487023e-14, -2.810333602750875e-17, -2.9082547001312045e-21]; \ No newline at end of file + 2.9082547001312045e-21, + 2.810333602750875e-17, + 2.8786070805487023e-14, + 8.106186297463033e-12, + 9.178580424378485e-10, + 5.108522450775958e-08, + 1.579094887324711e-06, + 2.938725228922988e-05, + 0.00034831012431868485, + 0.0027379224730676565, + 0.014703829704826678, + 0.055144176870234186, + 0.14673584754089003, + 0.28013093083921264, + 0.38639488954181395, + 0.38639488954181395, + 0.28013093083921264, + 0.14673584754089003, + 0.055144176870234186, + 0.014703829704826678, + 0.0027379224730676565, + 0.00034831012431868485, + 2.938725228922988e-05, + 1.579094887324711e-06, + 5.108522450775958e-08, + 9.178580424378485e-10, + 8.106186297463033e-12, + 2.8786070805487023e-14, + 2.810333602750875e-17, + 2.9082547001312045e-21, +]; diff --git a/src/utils/gl_table.rs b/src/utils/gl_table.rs index 2205fa2..1d7dc43 100644 --- a/src/utils/gl_table.rs +++ b/src/utils/gl_table.rs @@ -2,10 +2,11 @@ use crate::utils::error_codes::GAUSSIAN_QUADRATURE_ORDER_OUT_OF_RANGE; pub const MAX_GL_ORDER: usize = 30; -pub fn get_gl_weights_and_abscissae(order: usize, index: usize) -> Result<(f64, f64), &'static str> -{ - let ref_abs: f64 = match order - { +pub fn get_gl_weights_and_abscissae( + order: usize, + index: usize, +) -> Result<(f64, f64), &'static str> { + let ref_abs: f64 = match order { 1 => LEGENDRE_ABSCISSA_1[index], 2 => LEGENDRE_ABSCISSA_2[index], 3 => LEGENDRE_ABSCISSA_3[index], @@ -39,8 +40,7 @@ pub fn get_gl_weights_and_abscissae(order: usize, index: usize) -> Result<(f64, _ => return Err(GAUSSIAN_QUADRATURE_ORDER_OUT_OF_RANGE), }; - let ref_weight: f64 = match order - { + let ref_weight: f64 = match order { 1 => LEGENDRE_WEIGHT_1[index], 2 => LEGENDRE_WEIGHT_2[index], 3 => LEGENDRE_WEIGHT_3[index], @@ -77,998 +77,1039 @@ pub fn get_gl_weights_and_abscissae(order: usize, index: usize) -> Result<(f64, return Ok((ref_abs, ref_weight)); } - // ============================================================================= // Table generated using Python's numpy.polynomial.legendre // ============================================================================= -const LEGENDRE_ABSCISSA_1: [f64; 1] = [ -0.0]; -const LEGENDRE_ABSCISSA_2: [f64; 2] = [ --0.5773502691896257, -0.5773502691896257]; -const LEGENDRE_ABSCISSA_3: [f64; 3] = [ --0.7745966692414834, -0.0, -0.7745966692414834]; +const LEGENDRE_ABSCISSA_1: [f64; 1] = [0.0]; +const LEGENDRE_ABSCISSA_2: [f64; 2] = [-0.5773502691896257, 0.5773502691896257]; +const LEGENDRE_ABSCISSA_3: [f64; 3] = [-0.7745966692414834, 0.0, 0.7745966692414834]; const LEGENDRE_ABSCISSA_4: [f64; 4] = [ --0.8611363115940526, --0.33998104358485626, -0.33998104358485626, -0.8611363115940526]; + -0.8611363115940526, + -0.33998104358485626, + 0.33998104358485626, + 0.8611363115940526, +]; const LEGENDRE_ABSCISSA_5: [f64; 5] = [ --0.906179845938664, --0.5384693101056831, -0.0, -0.5384693101056831, -0.906179845938664]; + -0.906179845938664, + -0.5384693101056831, + 0.0, + 0.5384693101056831, + 0.906179845938664, +]; const LEGENDRE_ABSCISSA_6: [f64; 6] = [ --0.932469514203152, --0.6612093864662645, --0.23861918608319693, -0.23861918608319693, -0.6612093864662645, -0.932469514203152]; + -0.932469514203152, + -0.6612093864662645, + -0.23861918608319693, + 0.23861918608319693, + 0.6612093864662645, + 0.932469514203152, +]; const LEGENDRE_ABSCISSA_7: [f64; 7] = [ --0.9491079123427585, --0.7415311855993945, --0.4058451513773972, -0.0, -0.4058451513773972, -0.7415311855993945, -0.9491079123427585]; + -0.9491079123427585, + -0.7415311855993945, + -0.4058451513773972, + 0.0, + 0.4058451513773972, + 0.7415311855993945, + 0.9491079123427585, +]; const LEGENDRE_ABSCISSA_8: [f64; 8] = [ --0.9602898564975362, --0.7966664774136267, --0.525532409916329, --0.18343464249564978, -0.18343464249564978, -0.525532409916329, -0.7966664774136267, -0.9602898564975362]; + -0.9602898564975362, + -0.7966664774136267, + -0.525532409916329, + -0.18343464249564978, + 0.18343464249564978, + 0.525532409916329, + 0.7966664774136267, + 0.9602898564975362, +]; const LEGENDRE_ABSCISSA_9: [f64; 9] = [ --0.9681602395076261, --0.8360311073266358, --0.6133714327005904, --0.3242534234038089, -0.0, -0.3242534234038089, -0.6133714327005904, -0.8360311073266358, -0.9681602395076261]; + -0.9681602395076261, + -0.8360311073266358, + -0.6133714327005904, + -0.3242534234038089, + 0.0, + 0.3242534234038089, + 0.6133714327005904, + 0.8360311073266358, + 0.9681602395076261, +]; const LEGENDRE_ABSCISSA_10: [f64; 10] = [ --0.9739065285171717, --0.8650633666889845, --0.6794095682990244, --0.4333953941292472, --0.14887433898163122, -0.14887433898163122, -0.4333953941292472, -0.6794095682990244, -0.8650633666889845, -0.9739065285171717]; + -0.9739065285171717, + -0.8650633666889845, + -0.6794095682990244, + -0.4333953941292472, + -0.14887433898163122, + 0.14887433898163122, + 0.4333953941292472, + 0.6794095682990244, + 0.8650633666889845, + 0.9739065285171717, +]; const LEGENDRE_ABSCISSA_11: [f64; 11] = [ --0.978228658146057, --0.8870625997680953, --0.7301520055740494, --0.5190961292068118, --0.26954315595234496, -0.0, -0.26954315595234496, -0.5190961292068118, -0.7301520055740494, -0.8870625997680953, -0.978228658146057]; + -0.978228658146057, + -0.8870625997680953, + -0.7301520055740494, + -0.5190961292068118, + -0.26954315595234496, + 0.0, + 0.26954315595234496, + 0.5190961292068118, + 0.7301520055740494, + 0.8870625997680953, + 0.978228658146057, +]; const LEGENDRE_ABSCISSA_12: [f64; 12] = [ --0.9815606342467192, --0.9041172563704748, --0.7699026741943047, --0.5873179542866175, --0.3678314989981802, --0.1252334085114689, -0.1252334085114689, -0.3678314989981802, -0.5873179542866175, -0.7699026741943047, -0.9041172563704748, -0.9815606342467192]; + -0.9815606342467192, + -0.9041172563704748, + -0.7699026741943047, + -0.5873179542866175, + -0.3678314989981802, + -0.1252334085114689, + 0.1252334085114689, + 0.3678314989981802, + 0.5873179542866175, + 0.7699026741943047, + 0.9041172563704748, + 0.9815606342467192, +]; const LEGENDRE_ABSCISSA_13: [f64; 13] = [ --0.9841830547185881, --0.9175983992229779, --0.8015780907333099, --0.6423493394403402, --0.4484927510364468, --0.23045831595513477, -0.0, -0.23045831595513477, -0.4484927510364468, -0.6423493394403402, -0.8015780907333099, -0.9175983992229779, -0.9841830547185881]; + -0.9841830547185881, + -0.9175983992229779, + -0.8015780907333099, + -0.6423493394403402, + -0.4484927510364468, + -0.23045831595513477, + 0.0, + 0.23045831595513477, + 0.4484927510364468, + 0.6423493394403402, + 0.8015780907333099, + 0.9175983992229779, + 0.9841830547185881, +]; const LEGENDRE_ABSCISSA_14: [f64; 14] = [ --0.9862838086968123, --0.9284348836635735, --0.827201315069765, --0.6872929048116855, --0.5152486363581541, --0.31911236892788974, --0.10805494870734367, -0.10805494870734367, -0.31911236892788974, -0.5152486363581541, -0.6872929048116855, -0.827201315069765, -0.9284348836635735, -0.9862838086968123]; + -0.9862838086968123, + -0.9284348836635735, + -0.827201315069765, + -0.6872929048116855, + -0.5152486363581541, + -0.31911236892788974, + -0.10805494870734367, + 0.10805494870734367, + 0.31911236892788974, + 0.5152486363581541, + 0.6872929048116855, + 0.827201315069765, + 0.9284348836635735, + 0.9862838086968123, +]; const LEGENDRE_ABSCISSA_15: [f64; 15] = [ --0.9879925180204854, --0.937273392400706, --0.8482065834104272, --0.7244177313601701, --0.5709721726085388, --0.3941513470775634, --0.20119409399743451, -0.0, -0.20119409399743451, -0.3941513470775634, -0.5709721726085388, -0.7244177313601701, -0.8482065834104272, -0.937273392400706, -0.9879925180204854]; + -0.9879925180204854, + -0.937273392400706, + -0.8482065834104272, + -0.7244177313601701, + -0.5709721726085388, + -0.3941513470775634, + -0.20119409399743451, + 0.0, + 0.20119409399743451, + 0.3941513470775634, + 0.5709721726085388, + 0.7244177313601701, + 0.8482065834104272, + 0.937273392400706, + 0.9879925180204854, +]; const LEGENDRE_ABSCISSA_16: [f64; 16] = [ --0.9894009349916499, --0.9445750230732326, --0.8656312023878318, --0.755404408355003, --0.6178762444026438, --0.45801677765722737, --0.2816035507792589, --0.09501250983763745, -0.09501250983763745, -0.2816035507792589, -0.45801677765722737, -0.6178762444026438, -0.755404408355003, -0.8656312023878318, -0.9445750230732326, -0.9894009349916499]; + -0.9894009349916499, + -0.9445750230732326, + -0.8656312023878318, + -0.755404408355003, + -0.6178762444026438, + -0.45801677765722737, + -0.2816035507792589, + -0.09501250983763745, + 0.09501250983763745, + 0.2816035507792589, + 0.45801677765722737, + 0.6178762444026438, + 0.755404408355003, + 0.8656312023878318, + 0.9445750230732326, + 0.9894009349916499, +]; const LEGENDRE_ABSCISSA_17: [f64; 17] = [ --0.9905754753144174, --0.9506755217687678, --0.8802391537269859, --0.7815140038968014, --0.6576711592166908, --0.5126905370864769, --0.3512317634538763, --0.17848418149584785, -0.0, -0.17848418149584785, -0.3512317634538763, -0.5126905370864769, -0.6576711592166908, -0.7815140038968014, -0.8802391537269859, -0.9506755217687678, -0.9905754753144174]; + -0.9905754753144174, + -0.9506755217687678, + -0.8802391537269859, + -0.7815140038968014, + -0.6576711592166908, + -0.5126905370864769, + -0.3512317634538763, + -0.17848418149584785, + 0.0, + 0.17848418149584785, + 0.3512317634538763, + 0.5126905370864769, + 0.6576711592166908, + 0.7815140038968014, + 0.8802391537269859, + 0.9506755217687678, + 0.9905754753144174, +]; const LEGENDRE_ABSCISSA_18: [f64; 18] = [ --0.9915651684209309, --0.9558239495713978, --0.8926024664975557, --0.8037049589725231, --0.6916870430603532, --0.5597708310739475, --0.41175116146284263, --0.2518862256915055, --0.08477501304173529, -0.08477501304173529, -0.2518862256915055, -0.41175116146284263, -0.5597708310739475, -0.6916870430603532, -0.8037049589725231, -0.8926024664975557, -0.9558239495713978, -0.9915651684209309]; + -0.9915651684209309, + -0.9558239495713978, + -0.8926024664975557, + -0.8037049589725231, + -0.6916870430603532, + -0.5597708310739475, + -0.41175116146284263, + -0.2518862256915055, + -0.08477501304173529, + 0.08477501304173529, + 0.2518862256915055, + 0.41175116146284263, + 0.5597708310739475, + 0.6916870430603532, + 0.8037049589725231, + 0.8926024664975557, + 0.9558239495713978, + 0.9915651684209309, +]; const LEGENDRE_ABSCISSA_19: [f64; 19] = [ --0.9924068438435844, --0.96020815213483, --0.9031559036148179, --0.8227146565371428, --0.7209661773352294, --0.600545304661681, --0.46457074137596094, --0.31656409996362983, --0.1603586456402254, -0.0, -0.1603586456402254, -0.31656409996362983, -0.46457074137596094, -0.600545304661681, -0.7209661773352294, -0.8227146565371428, -0.9031559036148179, -0.96020815213483, -0.9924068438435844]; + -0.9924068438435844, + -0.96020815213483, + -0.9031559036148179, + -0.8227146565371428, + -0.7209661773352294, + -0.600545304661681, + -0.46457074137596094, + -0.31656409996362983, + -0.1603586456402254, + 0.0, + 0.1603586456402254, + 0.31656409996362983, + 0.46457074137596094, + 0.600545304661681, + 0.7209661773352294, + 0.8227146565371428, + 0.9031559036148179, + 0.96020815213483, + 0.9924068438435844, +]; const LEGENDRE_ABSCISSA_20: [f64; 20] = [ --0.9931285991850949, --0.9639719272779138, --0.9122344282513258, --0.8391169718222188, --0.7463319064601508, --0.636053680726515, --0.5108670019508271, --0.37370608871541955, --0.2277858511416451, --0.07652652113349734, -0.07652652113349734, -0.2277858511416451, -0.37370608871541955, -0.5108670019508271, -0.636053680726515, -0.7463319064601508, -0.8391169718222188, -0.9122344282513258, -0.9639719272779138, -0.9931285991850949]; + -0.9931285991850949, + -0.9639719272779138, + -0.9122344282513258, + -0.8391169718222188, + -0.7463319064601508, + -0.636053680726515, + -0.5108670019508271, + -0.37370608871541955, + -0.2277858511416451, + -0.07652652113349734, + 0.07652652113349734, + 0.2277858511416451, + 0.37370608871541955, + 0.5108670019508271, + 0.636053680726515, + 0.7463319064601508, + 0.8391169718222188, + 0.9122344282513258, + 0.9639719272779138, + 0.9931285991850949, +]; const LEGENDRE_ABSCISSA_21: [f64; 21] = [ --0.9937521706203895, --0.9672268385663063, --0.9200993341504008, --0.8533633645833173, --0.7684399634756779, --0.6671388041974123, --0.5516188358872198, --0.4243421202074388, --0.2880213168024011, --0.1455618541608951, -0.0, -0.1455618541608951, -0.2880213168024011, -0.4243421202074388, -0.5516188358872198, -0.6671388041974123, -0.7684399634756779, -0.8533633645833173, -0.9200993341504008, -0.9672268385663063, -0.9937521706203895]; + -0.9937521706203895, + -0.9672268385663063, + -0.9200993341504008, + -0.8533633645833173, + -0.7684399634756779, + -0.6671388041974123, + -0.5516188358872198, + -0.4243421202074388, + -0.2880213168024011, + -0.1455618541608951, + 0.0, + 0.1455618541608951, + 0.2880213168024011, + 0.4243421202074388, + 0.5516188358872198, + 0.6671388041974123, + 0.7684399634756779, + 0.8533633645833173, + 0.9200993341504008, + 0.9672268385663063, + 0.9937521706203895, +]; const LEGENDRE_ABSCISSA_22: [f64; 22] = [ --0.9942945854823992, --0.9700604978354287, --0.926956772187174, --0.8658125777203002, --0.7878168059792081, --0.6944872631866827, --0.5876404035069116, --0.46935583798675706, --0.34193582089208424, --0.2078604266882213, --0.06973927331972221, -0.06973927331972221, -0.2078604266882213, -0.34193582089208424, -0.46935583798675706, -0.5876404035069116, -0.6944872631866827, -0.7878168059792081, -0.8658125777203002, -0.926956772187174, -0.9700604978354287, -0.9942945854823992]; + -0.9942945854823992, + -0.9700604978354287, + -0.926956772187174, + -0.8658125777203002, + -0.7878168059792081, + -0.6944872631866827, + -0.5876404035069116, + -0.46935583798675706, + -0.34193582089208424, + -0.2078604266882213, + -0.06973927331972221, + 0.06973927331972221, + 0.2078604266882213, + 0.34193582089208424, + 0.46935583798675706, + 0.5876404035069116, + 0.6944872631866827, + 0.7878168059792081, + 0.8658125777203002, + 0.926956772187174, + 0.9700604978354287, + 0.9942945854823992, +]; const LEGENDRE_ABSCISSA_23: [f64; 23] = [ --0.9947693349975522, --0.9725424712181152, --0.9329710868260161, --0.8767523582704416, --0.8048884016188399, --0.7186613631319502, --0.6196098757636461, --0.5095014778460075, --0.3903010380302908, --0.26413568097034495, --0.1332568242984661, -0.0, -0.1332568242984661, -0.26413568097034495, -0.3903010380302908, -0.5095014778460075, -0.6196098757636461, -0.7186613631319502, -0.8048884016188399, -0.8767523582704416, -0.9329710868260161, -0.9725424712181152, -0.9947693349975522]; + -0.9947693349975522, + -0.9725424712181152, + -0.9329710868260161, + -0.8767523582704416, + -0.8048884016188399, + -0.7186613631319502, + -0.6196098757636461, + -0.5095014778460075, + -0.3903010380302908, + -0.26413568097034495, + -0.1332568242984661, + 0.0, + 0.1332568242984661, + 0.26413568097034495, + 0.3903010380302908, + 0.5095014778460075, + 0.6196098757636461, + 0.7186613631319502, + 0.8048884016188399, + 0.8767523582704416, + 0.9329710868260161, + 0.9725424712181152, + 0.9947693349975522, +]; const LEGENDRE_ABSCISSA_24: [f64; 24] = [ --0.9951872199970213, --0.9747285559713095, --0.9382745520027328, --0.886415527004401, --0.820001985973903, --0.7401241915785544, --0.6480936519369755, --0.5454214713888396, --0.4337935076260451, --0.3150426796961634, --0.1911188674736163, --0.06405689286260563, -0.06405689286260563, -0.1911188674736163, -0.3150426796961634, -0.4337935076260451, -0.5454214713888396, -0.6480936519369755, -0.7401241915785544, -0.820001985973903, -0.886415527004401, -0.9382745520027328, -0.9747285559713095, -0.9951872199970213]; + -0.9951872199970213, + -0.9747285559713095, + -0.9382745520027328, + -0.886415527004401, + -0.820001985973903, + -0.7401241915785544, + -0.6480936519369755, + -0.5454214713888396, + -0.4337935076260451, + -0.3150426796961634, + -0.1911188674736163, + -0.06405689286260563, + 0.06405689286260563, + 0.1911188674736163, + 0.3150426796961634, + 0.4337935076260451, + 0.5454214713888396, + 0.6480936519369755, + 0.7401241915785544, + 0.820001985973903, + 0.886415527004401, + 0.9382745520027328, + 0.9747285559713095, + 0.9951872199970213, +]; const LEGENDRE_ABSCISSA_25: [f64; 25] = [ --0.995556969790498, --0.9766639214595175, --0.9429745712289743, --0.8949919978782753, --0.833442628760834, --0.7592592630373576, --0.6735663684734684, --0.577662930241223, --0.473002731445715, --0.36117230580938786, --0.24386688372098841, --0.1228646926107104, -0.0, -0.1228646926107104, -0.24386688372098841, -0.36117230580938786, -0.473002731445715, -0.577662930241223, -0.6735663684734684, -0.7592592630373576, -0.833442628760834, -0.8949919978782753, -0.9429745712289743, -0.9766639214595175, -0.995556969790498]; + -0.995556969790498, + -0.9766639214595175, + -0.9429745712289743, + -0.8949919978782753, + -0.833442628760834, + -0.7592592630373576, + -0.6735663684734684, + -0.577662930241223, + -0.473002731445715, + -0.36117230580938786, + -0.24386688372098841, + -0.1228646926107104, + 0.0, + 0.1228646926107104, + 0.24386688372098841, + 0.36117230580938786, + 0.473002731445715, + 0.577662930241223, + 0.6735663684734684, + 0.7592592630373576, + 0.833442628760834, + 0.8949919978782753, + 0.9429745712289743, + 0.9766639214595175, + 0.995556969790498, +]; const LEGENDRE_ABSCISSA_26: [f64; 26] = [ --0.9958857011456169, --0.9783854459564709, --0.9471590666617142, --0.9026378619843071, --0.845445942788498, --0.7763859488206788, --0.6964272604199573, --0.6066922930176181, --0.5084407148245057, --0.4030517551234863, --0.2920048394859569, --0.17685882035689018, --0.05923009342931321, -0.05923009342931321, -0.17685882035689018, -0.2920048394859569, -0.4030517551234863, -0.5084407148245057, -0.6066922930176181, -0.6964272604199573, -0.7763859488206788, -0.845445942788498, -0.9026378619843071, -0.9471590666617142, -0.9783854459564709, -0.9958857011456169]; + -0.9958857011456169, + -0.9783854459564709, + -0.9471590666617142, + -0.9026378619843071, + -0.845445942788498, + -0.7763859488206788, + -0.6964272604199573, + -0.6066922930176181, + -0.5084407148245057, + -0.4030517551234863, + -0.2920048394859569, + -0.17685882035689018, + -0.05923009342931321, + 0.05923009342931321, + 0.17685882035689018, + 0.2920048394859569, + 0.4030517551234863, + 0.5084407148245057, + 0.6066922930176181, + 0.6964272604199573, + 0.7763859488206788, + 0.845445942788498, + 0.9026378619843071, + 0.9471590666617142, + 0.9783854459564709, + 0.9958857011456169, +]; const LEGENDRE_ABSCISSA_27: [f64; 27] = [ --0.9961792628889885, --0.9799234759615012, --0.9509005578147051, --0.9094823206774911, --0.8562079080182945, --0.7917716390705083, --0.7170134737394237, --0.6329079719464952, --0.540551564579457, --0.44114825175002687, --0.3359939036385089, --0.22645936543953685, --0.11397258560952997, -0.0, -0.11397258560952997, -0.22645936543953685, -0.3359939036385089, -0.44114825175002687, -0.540551564579457, -0.6329079719464952, -0.7170134737394237, -0.7917716390705083, -0.8562079080182945, -0.9094823206774911, -0.9509005578147051, -0.9799234759615012, -0.9961792628889885]; + -0.9961792628889885, + -0.9799234759615012, + -0.9509005578147051, + -0.9094823206774911, + -0.8562079080182945, + -0.7917716390705083, + -0.7170134737394237, + -0.6329079719464952, + -0.540551564579457, + -0.44114825175002687, + -0.3359939036385089, + -0.22645936543953685, + -0.11397258560952997, + 0.0, + 0.11397258560952997, + 0.22645936543953685, + 0.3359939036385089, + 0.44114825175002687, + 0.540551564579457, + 0.6329079719464952, + 0.7170134737394237, + 0.7917716390705083, + 0.8562079080182945, + 0.9094823206774911, + 0.9509005578147051, + 0.9799234759615012, + 0.9961792628889885, +]; const LEGENDRE_ABSCISSA_28: [f64; 28] = [ --0.9964424975739544, --0.9813031653708728, --0.9542592806289382, --0.9156330263921321, --0.865892522574395, --0.8056413709171791, --0.7356108780136318, --0.656651094038865, --0.5697204718114017, --0.4758742249551183, --0.3762515160890787, --0.2720616276351781, --0.1645692821333808, --0.055079289884034266, -0.055079289884034266, -0.1645692821333808, -0.2720616276351781, -0.3762515160890787, -0.4758742249551183, -0.5697204718114017, -0.656651094038865, -0.7356108780136318, -0.8056413709171791, -0.865892522574395, -0.9156330263921321, -0.9542592806289382, -0.9813031653708728, -0.9964424975739544]; + -0.9964424975739544, + -0.9813031653708728, + -0.9542592806289382, + -0.9156330263921321, + -0.865892522574395, + -0.8056413709171791, + -0.7356108780136318, + -0.656651094038865, + -0.5697204718114017, + -0.4758742249551183, + -0.3762515160890787, + -0.2720616276351781, + -0.1645692821333808, + -0.055079289884034266, + 0.055079289884034266, + 0.1645692821333808, + 0.2720616276351781, + 0.3762515160890787, + 0.4758742249551183, + 0.5697204718114017, + 0.656651094038865, + 0.7356108780136318, + 0.8056413709171791, + 0.865892522574395, + 0.9156330263921321, + 0.9542592806289382, + 0.9813031653708728, + 0.9964424975739544, +]; const LEGENDRE_ABSCISSA_29: [f64; 29] = [ --0.9966794422605966, --0.9825455052614132, --0.9572855957780877, --0.9211802329530587, --0.8746378049201028, --0.8181854876152524, --0.7524628517344771, --0.6782145376026865, --0.5962817971382278, --0.5075929551242276, --0.41315288817400864, --0.31403163786763993, --0.21135228616600107, --0.10627823013267923, -0.0, -0.10627823013267923, -0.21135228616600107, -0.31403163786763993, -0.41315288817400864, -0.5075929551242276, -0.5962817971382278, -0.6782145376026865, -0.7524628517344771, -0.8181854876152524, -0.8746378049201028, -0.9211802329530587, -0.9572855957780877, -0.9825455052614132, -0.9966794422605966]; + -0.9966794422605966, + -0.9825455052614132, + -0.9572855957780877, + -0.9211802329530587, + -0.8746378049201028, + -0.8181854876152524, + -0.7524628517344771, + -0.6782145376026865, + -0.5962817971382278, + -0.5075929551242276, + -0.41315288817400864, + -0.31403163786763993, + -0.21135228616600107, + -0.10627823013267923, + 0.0, + 0.10627823013267923, + 0.21135228616600107, + 0.31403163786763993, + 0.41315288817400864, + 0.5075929551242276, + 0.5962817971382278, + 0.6782145376026865, + 0.7524628517344771, + 0.8181854876152524, + 0.8746378049201028, + 0.9211802329530587, + 0.9572855957780877, + 0.9825455052614132, + 0.9966794422605966, +]; const LEGENDRE_ABSCISSA_30: [f64; 30] = [ --0.9968934840746495, --0.9836681232797473, --0.9600218649683075, --0.9262000474292743, --0.8825605357920526, --0.8295657623827684, --0.7677774321048262, --0.6978504947933158, --0.6205261829892429, --0.5366241481420199, --0.44703376953808915, --0.3527047255308781, --0.25463692616788985, --0.15386991360858354, --0.0514718425553177, -0.0514718425553177, -0.15386991360858354, -0.25463692616788985, -0.3527047255308781, -0.44703376953808915, -0.5366241481420199, -0.6205261829892429, -0.6978504947933158, -0.7677774321048262, -0.8295657623827684, -0.8825605357920526, -0.9262000474292743, -0.9600218649683075, -0.9836681232797473, -0.9968934840746495]; + -0.9968934840746495, + -0.9836681232797473, + -0.9600218649683075, + -0.9262000474292743, + -0.8825605357920526, + -0.8295657623827684, + -0.7677774321048262, + -0.6978504947933158, + -0.6205261829892429, + -0.5366241481420199, + -0.44703376953808915, + -0.3527047255308781, + -0.25463692616788985, + -0.15386991360858354, + -0.0514718425553177, + 0.0514718425553177, + 0.15386991360858354, + 0.25463692616788985, + 0.3527047255308781, + 0.44703376953808915, + 0.5366241481420199, + 0.6205261829892429, + 0.6978504947933158, + 0.7677774321048262, + 0.8295657623827684, + 0.8825605357920526, + 0.9262000474292743, + 0.9600218649683075, + 0.9836681232797473, + 0.9968934840746495, +]; -const LEGENDRE_WEIGHT_1: [f64; 1] = [ -2.0]; -const LEGENDRE_WEIGHT_2: [f64; 2] = [ -1.0, -1.0]; -const LEGENDRE_WEIGHT_3: [f64; 3] = [ -0.5555555555555557, -0.8888888888888888, -0.5555555555555557]; +const LEGENDRE_WEIGHT_1: [f64; 1] = [2.0]; +const LEGENDRE_WEIGHT_2: [f64; 2] = [1.0, 1.0]; +const LEGENDRE_WEIGHT_3: [f64; 3] = [0.5555555555555557, 0.8888888888888888, 0.5555555555555557]; const LEGENDRE_WEIGHT_4: [f64; 4] = [ -0.3478548451374537, -0.6521451548625462, -0.6521451548625462, -0.3478548451374537]; + 0.3478548451374537, + 0.6521451548625462, + 0.6521451548625462, + 0.3478548451374537, +]; const LEGENDRE_WEIGHT_5: [f64; 5] = [ -0.23692688505618942, -0.4786286704993662, -0.568888888888889, -0.4786286704993662, -0.23692688505618942]; + 0.23692688505618942, + 0.4786286704993662, + 0.568888888888889, + 0.4786286704993662, + 0.23692688505618942, +]; const LEGENDRE_WEIGHT_6: [f64; 6] = [ -0.17132449237916975, -0.36076157304813894, -0.46791393457269137, -0.46791393457269137, -0.36076157304813894, -0.17132449237916975]; + 0.17132449237916975, + 0.36076157304813894, + 0.46791393457269137, + 0.46791393457269137, + 0.36076157304813894, + 0.17132449237916975, +]; const LEGENDRE_WEIGHT_7: [f64; 7] = [ -0.12948496616887065, -0.2797053914892766, -0.3818300505051183, -0.41795918367346896, -0.3818300505051183, -0.2797053914892766, -0.12948496616887065]; + 0.12948496616887065, + 0.2797053914892766, + 0.3818300505051183, + 0.41795918367346896, + 0.3818300505051183, + 0.2797053914892766, + 0.12948496616887065, +]; const LEGENDRE_WEIGHT_8: [f64; 8] = [ -0.10122853629037669, -0.22238103445337434, -0.31370664587788705, -0.36268378337836177, -0.36268378337836177, -0.31370664587788705, -0.22238103445337434, -0.10122853629037669]; + 0.10122853629037669, + 0.22238103445337434, + 0.31370664587788705, + 0.36268378337836177, + 0.36268378337836177, + 0.31370664587788705, + 0.22238103445337434, + 0.10122853629037669, +]; const LEGENDRE_WEIGHT_9: [f64; 9] = [ -0.08127438836157472, -0.18064816069485712, -0.26061069640293566, -0.3123470770400028, -0.33023935500125967, -0.3123470770400028, -0.26061069640293566, -0.18064816069485712, -0.08127438836157472]; + 0.08127438836157472, + 0.18064816069485712, + 0.26061069640293566, + 0.3123470770400028, + 0.33023935500125967, + 0.3123470770400028, + 0.26061069640293566, + 0.18064816069485712, + 0.08127438836157472, +]; const LEGENDRE_WEIGHT_10: [f64; 10] = [ -0.06667134430868807, -0.14945134915058036, -0.219086362515982, -0.2692667193099965, -0.295524224714753, -0.295524224714753, -0.2692667193099965, -0.219086362515982, -0.14945134915058036, -0.06667134430868807]; + 0.06667134430868807, + 0.14945134915058036, + 0.219086362515982, + 0.2692667193099965, + 0.295524224714753, + 0.295524224714753, + 0.2692667193099965, + 0.219086362515982, + 0.14945134915058036, + 0.06667134430868807, +]; const LEGENDRE_WEIGHT_11: [f64; 11] = [ -0.055668567116173164, -0.1255803694649047, -0.18629021092773443, -0.23319376459199068, -0.26280454451024676, -0.2729250867779009, -0.26280454451024676, -0.23319376459199068, -0.18629021092773443, -0.1255803694649047, -0.055668567116173164]; + 0.055668567116173164, + 0.1255803694649047, + 0.18629021092773443, + 0.23319376459199068, + 0.26280454451024676, + 0.2729250867779009, + 0.26280454451024676, + 0.23319376459199068, + 0.18629021092773443, + 0.1255803694649047, + 0.055668567116173164, +]; const LEGENDRE_WEIGHT_12: [f64; 12] = [ -0.04717533638651202, -0.10693932599531888, -0.1600783285433461, -0.20316742672306565, -0.23349253653835464, -0.2491470458134027, -0.2491470458134027, -0.23349253653835464, -0.20316742672306565, -0.1600783285433461, -0.10693932599531888, -0.04717533638651202]; + 0.04717533638651202, + 0.10693932599531888, + 0.1600783285433461, + 0.20316742672306565, + 0.23349253653835464, + 0.2491470458134027, + 0.2491470458134027, + 0.23349253653835464, + 0.20316742672306565, + 0.1600783285433461, + 0.10693932599531888, + 0.04717533638651202, +]; const LEGENDRE_WEIGHT_13: [f64; 13] = [ -0.04048400476531588, -0.0921214998377286, -0.13887351021978736, -0.17814598076194552, -0.20781604753688857, -0.22628318026289715, -0.2325515532308739, -0.22628318026289715, -0.20781604753688857, -0.17814598076194552, -0.13887351021978736, -0.0921214998377286, -0.04048400476531588]; + 0.04048400476531588, + 0.0921214998377286, + 0.13887351021978736, + 0.17814598076194552, + 0.20781604753688857, + 0.22628318026289715, + 0.2325515532308739, + 0.22628318026289715, + 0.20781604753688857, + 0.17814598076194552, + 0.13887351021978736, + 0.0921214998377286, + 0.04048400476531588, +]; const LEGENDRE_WEIGHT_14: [f64; 14] = [ -0.035119460331752374, -0.0801580871597603, -0.12151857068790296, -0.1572031671581934, -0.18553839747793763, -0.20519846372129555, -0.21526385346315766, -0.21526385346315766, -0.20519846372129555, -0.18553839747793763, -0.1572031671581934, -0.12151857068790296, -0.0801580871597603, -0.035119460331752374]; + 0.035119460331752374, + 0.0801580871597603, + 0.12151857068790296, + 0.1572031671581934, + 0.18553839747793763, + 0.20519846372129555, + 0.21526385346315766, + 0.21526385346315766, + 0.20519846372129555, + 0.18553839747793763, + 0.1572031671581934, + 0.12151857068790296, + 0.0801580871597603, + 0.035119460331752374, +]; const LEGENDRE_WEIGHT_15: [f64; 15] = [ -0.030753241996118647, -0.07036604748810807, -0.10715922046717177, -0.1395706779261539, -0.16626920581699378, -0.18616100001556188, -0.19843148532711125, -0.2025782419255609, -0.19843148532711125, -0.18616100001556188, -0.16626920581699378, -0.1395706779261539, -0.10715922046717177, -0.07036604748810807, -0.030753241996118647]; + 0.030753241996118647, + 0.07036604748810807, + 0.10715922046717177, + 0.1395706779261539, + 0.16626920581699378, + 0.18616100001556188, + 0.19843148532711125, + 0.2025782419255609, + 0.19843148532711125, + 0.18616100001556188, + 0.16626920581699378, + 0.1395706779261539, + 0.10715922046717177, + 0.07036604748810807, + 0.030753241996118647, +]; const LEGENDRE_WEIGHT_16: [f64; 16] = [ -0.027152459411754037, -0.062253523938647706, -0.09515851168249259, -0.12462897125553403, -0.14959598881657676, -0.16915651939500262, -0.1826034150449236, -0.18945061045506859, -0.18945061045506859, -0.1826034150449236, -0.16915651939500262, -0.14959598881657676, -0.12462897125553403, -0.09515851168249259, -0.062253523938647706, -0.027152459411754037]; + 0.027152459411754037, + 0.062253523938647706, + 0.09515851168249259, + 0.12462897125553403, + 0.14959598881657676, + 0.16915651939500262, + 0.1826034150449236, + 0.18945061045506859, + 0.18945061045506859, + 0.1826034150449236, + 0.16915651939500262, + 0.14959598881657676, + 0.12462897125553403, + 0.09515851168249259, + 0.062253523938647706, + 0.027152459411754037, +]; const LEGENDRE_WEIGHT_17: [f64; 17] = [ -0.02414830286854952, -0.0554595293739866, -0.08503614831717908, -0.11188384719340365, -0.13513636846852523, -0.15404576107681012, -0.16800410215644995, -0.17656270536699253, -0.17944647035620653, -0.17656270536699253, -0.16800410215644995, -0.15404576107681012, -0.13513636846852523, -0.11188384719340365, -0.08503614831717908, -0.0554595293739866, -0.02414830286854952]; + 0.02414830286854952, + 0.0554595293739866, + 0.08503614831717908, + 0.11188384719340365, + 0.13513636846852523, + 0.15404576107681012, + 0.16800410215644995, + 0.17656270536699253, + 0.17944647035620653, + 0.17656270536699253, + 0.16800410215644995, + 0.15404576107681012, + 0.13513636846852523, + 0.11188384719340365, + 0.08503614831717908, + 0.0554595293739866, + 0.02414830286854952, +]; const LEGENDRE_WEIGHT_18: [f64; 18] = [ -0.02161601352648413, -0.04971454889496922, -0.07642573025488925, -0.10094204410628699, -0.12255520671147836, -0.14064291467065063, -0.15468467512626521, -0.16427648374583273, -0.16914238296314363, -0.16914238296314363, -0.16427648374583273, -0.15468467512626521, -0.14064291467065063, -0.12255520671147836, -0.10094204410628699, -0.07642573025488925, -0.04971454889496922, -0.02161601352648413]; + 0.02161601352648413, + 0.04971454889496922, + 0.07642573025488925, + 0.10094204410628699, + 0.12255520671147836, + 0.14064291467065063, + 0.15468467512626521, + 0.16427648374583273, + 0.16914238296314363, + 0.16914238296314363, + 0.16427648374583273, + 0.15468467512626521, + 0.14064291467065063, + 0.12255520671147836, + 0.10094204410628699, + 0.07642573025488925, + 0.04971454889496922, + 0.02161601352648413, +]; const LEGENDRE_WEIGHT_19: [f64; 19] = [ -0.01946178822972761, -0.04481422676569981, -0.06904454273764107, -0.09149002162244985, -0.11156664554733375, -0.1287539625393362, -0.14260670217360638, -0.15276604206585945, -0.15896884339395415, -0.16105444984878345, -0.15896884339395415, -0.15276604206585945, -0.14260670217360638, -0.1287539625393362, -0.11156664554733375, -0.09149002162244985, -0.06904454273764107, -0.04481422676569981, -0.01946178822972761]; + 0.01946178822972761, + 0.04481422676569981, + 0.06904454273764107, + 0.09149002162244985, + 0.11156664554733375, + 0.1287539625393362, + 0.14260670217360638, + 0.15276604206585945, + 0.15896884339395415, + 0.16105444984878345, + 0.15896884339395415, + 0.15276604206585945, + 0.14260670217360638, + 0.1287539625393362, + 0.11156664554733375, + 0.09149002162244985, + 0.06904454273764107, + 0.04481422676569981, + 0.01946178822972761, +]; const LEGENDRE_WEIGHT_20: [f64; 20] = [ -0.017614007139153273, -0.04060142980038622, -0.06267204833410944, -0.08327674157670467, -0.10193011981724026, -0.11819453196151825, -0.13168863844917653, -0.14209610931838187, -0.14917298647260366, -0.15275338713072578, -0.15275338713072578, -0.14917298647260366, -0.14209610931838187, -0.13168863844917653, -0.11819453196151825, -0.10193011981724026, -0.08327674157670467, -0.06267204833410944, -0.04060142980038622, -0.017614007139153273]; + 0.017614007139153273, + 0.04060142980038622, + 0.06267204833410944, + 0.08327674157670467, + 0.10193011981724026, + 0.11819453196151825, + 0.13168863844917653, + 0.14209610931838187, + 0.14917298647260366, + 0.15275338713072578, + 0.15275338713072578, + 0.14917298647260366, + 0.14209610931838187, + 0.13168863844917653, + 0.11819453196151825, + 0.10193011981724026, + 0.08327674157670467, + 0.06267204833410944, + 0.04060142980038622, + 0.017614007139153273, +]; const LEGENDRE_WEIGHT_21: [f64; 21] = [ -0.016017228257774137, -0.03695378977085292, -0.057134425426857156, -0.07610011362837935, -0.09344442345603382, -0.10879729916714831, -0.12183141605372842, -0.13226893863333739, -0.13988739479107312, -0.14452440398997007, -0.14608113364969047, -0.14452440398997007, -0.13988739479107312, -0.13226893863333739, -0.12183141605372842, -0.10879729916714831, -0.09344442345603382, -0.07610011362837935, -0.057134425426857156, -0.03695378977085292, -0.016017228257774137]; + 0.016017228257774137, + 0.03695378977085292, + 0.057134425426857156, + 0.07610011362837935, + 0.09344442345603382, + 0.10879729916714831, + 0.12183141605372842, + 0.13226893863333739, + 0.13988739479107312, + 0.14452440398997007, + 0.14608113364969047, + 0.14452440398997007, + 0.13988739479107312, + 0.13226893863333739, + 0.12183141605372842, + 0.10879729916714831, + 0.09344442345603382, + 0.07610011362837935, + 0.057134425426857156, + 0.03695378977085292, + 0.016017228257774137, +]; const LEGENDRE_WEIGHT_22: [f64; 22] = [ -0.014627995298274705, -0.03377490158481518, -0.05229333515268287, -0.0697964684245202, -0.0859416062170674, -0.10041414444288072, -0.11293229608053883, -0.12325237681051199, -0.13117350478706188, -0.13654149834601478, -0.13925187285563156, -0.13925187285563156, -0.13654149834601478, -0.13117350478706188, -0.12325237681051199, -0.11293229608053883, -0.10041414444288072, -0.0859416062170674, -0.0697964684245202, -0.05229333515268287, -0.03377490158481518, -0.014627995298274705]; + 0.014627995298274705, + 0.03377490158481518, + 0.05229333515268287, + 0.0697964684245202, + 0.0859416062170674, + 0.10041414444288072, + 0.11293229608053883, + 0.12325237681051199, + 0.13117350478706188, + 0.13654149834601478, + 0.13925187285563156, + 0.13925187285563156, + 0.13654149834601478, + 0.13117350478706188, + 0.12325237681051199, + 0.11293229608053883, + 0.10041414444288072, + 0.0859416062170674, + 0.0697964684245202, + 0.05229333515268287, + 0.03377490158481518, + 0.014627995298274705, +]; const LEGENDRE_WEIGHT_23: [f64; 23] = [ -0.013411859487141846, -0.030988005856979497, -0.04803767173108495, -0.06423242140852606, -0.07928141177671887, -0.09291576606003524, -0.10489209146454138, -0.1149966402224113, -0.12304908430672945, -0.128905722188082, -0.13246203940469642, -0.13365457218610594, -0.13246203940469642, -0.128905722188082, -0.12304908430672945, -0.1149966402224113, -0.10489209146454138, -0.09291576606003524, -0.07928141177671887, -0.06423242140852606, -0.04803767173108495, -0.030988005856979497, -0.013411859487141846]; + 0.013411859487141846, + 0.030988005856979497, + 0.04803767173108495, + 0.06423242140852606, + 0.07928141177671887, + 0.09291576606003524, + 0.10489209146454138, + 0.1149966402224113, + 0.12304908430672945, + 0.128905722188082, + 0.13246203940469642, + 0.13365457218610594, + 0.13246203940469642, + 0.128905722188082, + 0.12304908430672945, + 0.1149966402224113, + 0.10489209146454138, + 0.09291576606003524, + 0.07928141177671887, + 0.06423242140852606, + 0.04803767173108495, + 0.030988005856979497, + 0.013411859487141846, +]; const LEGENDRE_WEIGHT_24: [f64; 24] = [ -0.012341229799987091, -0.028531388628933743, -0.04427743881741955, -0.05929858491543674, -0.07334648141108041, -0.08619016153195329, -0.09761865210411406, -0.1074442701159656, -0.11550566805372561, -0.12167047292780342, -0.1258374563468283, -0.12793819534675221, -0.12793819534675221, -0.1258374563468283, -0.12167047292780342, -0.11550566805372561, -0.1074442701159656, -0.09761865210411406, -0.08619016153195329, -0.07334648141108041, -0.05929858491543674, -0.04427743881741955, -0.028531388628933743, -0.012341229799987091]; + 0.012341229799987091, + 0.028531388628933743, + 0.04427743881741955, + 0.05929858491543674, + 0.07334648141108041, + 0.08619016153195329, + 0.09761865210411406, + 0.1074442701159656, + 0.11550566805372561, + 0.12167047292780342, + 0.1258374563468283, + 0.12793819534675221, + 0.12793819534675221, + 0.1258374563468283, + 0.12167047292780342, + 0.11550566805372561, + 0.1074442701159656, + 0.09761865210411406, + 0.08619016153195329, + 0.07334648141108041, + 0.05929858491543674, + 0.04427743881741955, + 0.028531388628933743, + 0.012341229799987091, +]; const LEGENDRE_WEIGHT_25: [f64; 25] = [ -0.011393798501027593, -0.026354986615031908, -0.0409391567013065, -0.05490469597583544, -0.06803833381235701, -0.08014070033500098, -0.09102826198296338, -0.10053594906705049, -0.10851962447426344, -0.11485825914571146, -0.1194557635357845, -0.12224244299030987, -0.12317605372671524, -0.12224244299030987, -0.1194557635357845, -0.11485825914571146, -0.10851962447426344, -0.10053594906705049, -0.09102826198296338, -0.08014070033500098, -0.06803833381235701, -0.05490469597583544, -0.0409391567013065, -0.026354986615031908, -0.011393798501027593]; + 0.011393798501027593, + 0.026354986615031908, + 0.0409391567013065, + 0.05490469597583544, + 0.06803833381235701, + 0.08014070033500098, + 0.09102826198296338, + 0.10053594906705049, + 0.10851962447426344, + 0.11485825914571146, + 0.1194557635357845, + 0.12224244299030987, + 0.12317605372671524, + 0.12224244299030987, + 0.1194557635357845, + 0.11485825914571146, + 0.10851962447426344, + 0.10053594906705049, + 0.09102826198296338, + 0.08014070033500098, + 0.06803833381235701, + 0.05490469597583544, + 0.0409391567013065, + 0.026354986615031908, + 0.011393798501027593, +]; const LEGENDRE_WEIGHT_26: [f64; 26] = [ -0.010551372617343395, -0.024417851092631938, -0.03796238329436312, -0.05097582529714808, -0.06327404632957467, -0.07468414976565976, -0.08504589431348507, -0.09421380035591416, -0.10205916109442532, -0.10847184052857647, -0.11336181654631956, -0.11666044348529646, -0.11832141527926213, -0.11832141527926213, -0.11666044348529646, -0.11336181654631956, -0.10847184052857647, -0.10205916109442532, -0.09421380035591416, -0.08504589431348507, -0.07468414976565976, -0.06327404632957467, -0.05097582529714808, -0.03796238329436312, -0.024417851092631938, -0.010551372617343395]; + 0.010551372617343395, + 0.024417851092631938, + 0.03796238329436312, + 0.05097582529714808, + 0.06327404632957467, + 0.07468414976565976, + 0.08504589431348507, + 0.09421380035591416, + 0.10205916109442532, + 0.10847184052857647, + 0.11336181654631956, + 0.11666044348529646, + 0.11832141527926213, + 0.11832141527926213, + 0.11666044348529646, + 0.11336181654631956, + 0.10847184052857647, + 0.10205916109442532, + 0.09421380035591416, + 0.08504589431348507, + 0.07468414976565976, + 0.06327404632957467, + 0.05097582529714808, + 0.03796238329436312, + 0.024417851092631938, + 0.010551372617343395, +]; const LEGENDRE_WEIGHT_27: [f64; 27] = [ -0.009798996051294204, -0.022686231596180995, -0.03529705375741918, -0.047449412520615374, -0.05898353685983364, -0.06974882376624564, -0.07960486777305782, -0.08842315854375683, -0.0960887273700285, -0.10250163781774586, -0.10757828578853317, -0.11125248835684516, -0.1134763461089652, -0.11422086737895706, -0.1134763461089652, -0.11125248835684516, -0.10757828578853317, -0.10250163781774586, -0.0960887273700285, -0.08842315854375683, -0.07960486777305782, -0.06974882376624564, -0.05898353685983364, -0.047449412520615374, -0.03529705375741918, -0.022686231596180995, -0.009798996051294204]; + 0.009798996051294204, + 0.022686231596180995, + 0.03529705375741918, + 0.047449412520615374, + 0.05898353685983364, + 0.06974882376624564, + 0.07960486777305782, + 0.08842315854375683, + 0.0960887273700285, + 0.10250163781774586, + 0.10757828578853317, + 0.11125248835684516, + 0.1134763461089652, + 0.11422086737895706, + 0.1134763461089652, + 0.11125248835684516, + 0.10757828578853317, + 0.10250163781774586, + 0.0960887273700285, + 0.08842315854375683, + 0.07960486777305782, + 0.06974882376624564, + 0.05898353685983364, + 0.047449412520615374, + 0.03529705375741918, + 0.022686231596180995, + 0.009798996051294204, +]; const LEGENDRE_WEIGHT_28: [f64; 28] = [ -0.009124282593094397, -0.02113211259277127, -0.03290142778230452, -0.044272934759003985, -0.055107345675716936, -0.06527292396699975, -0.07464621423456881, -0.08311341722890093, -0.09057174439303285, -0.09693065799792992, -0.10211296757806078, -0.10605576592284637, -0.10871119225829413, -0.11004701301647524, -0.11004701301647524, -0.10871119225829413, -0.10605576592284637, -0.10211296757806078, -0.09693065799792992, -0.09057174439303285, -0.08311341722890093, -0.07464621423456881, -0.06527292396699975, -0.055107345675716936, -0.044272934759003985, -0.03290142778230452, -0.02113211259277127, -0.009124282593094397]; + 0.009124282593094397, + 0.02113211259277127, + 0.03290142778230452, + 0.044272934759003985, + 0.055107345675716936, + 0.06527292396699975, + 0.07464621423456881, + 0.08311341722890093, + 0.09057174439303285, + 0.09693065799792992, + 0.10211296757806078, + 0.10605576592284637, + 0.10871119225829413, + 0.11004701301647524, + 0.11004701301647524, + 0.10871119225829413, + 0.10605576592284637, + 0.10211296757806078, + 0.09693065799792992, + 0.09057174439303285, + 0.08311341722890093, + 0.07464621423456881, + 0.06527292396699975, + 0.055107345675716936, + 0.044272934759003985, + 0.03290142778230452, + 0.02113211259277127, + 0.009124282593094397, +]; const LEGENDRE_WEIGHT_29: [f64; 29] = [ -0.008516903878747237, -0.019732085056123293, -0.03074049220209336, -0.04140206251868274, -0.051594826902497753, -0.06120309065707902, -0.07011793325505114, -0.07823832713576369, -0.0854722573661724, -0.0917377571392587, -0.09696383409440848, -0.10109127375991488, -0.10407331007772933, -0.10587615509732079, -0.10647938171831416, -0.10587615509732079, -0.10407331007772933, -0.10109127375991488, -0.09696383409440848, -0.0917377571392587, -0.0854722573661724, -0.07823832713576369, -0.07011793325505114, -0.06120309065707902, -0.051594826902497753, -0.04140206251868274, -0.03074049220209336, -0.019732085056123293, -0.008516903878747237]; + 0.008516903878747237, + 0.019732085056123293, + 0.03074049220209336, + 0.04140206251868274, + 0.051594826902497753, + 0.06120309065707902, + 0.07011793325505114, + 0.07823832713576369, + 0.0854722573661724, + 0.0917377571392587, + 0.09696383409440848, + 0.10109127375991488, + 0.10407331007772933, + 0.10587615509732079, + 0.10647938171831416, + 0.10587615509732079, + 0.10407331007772933, + 0.10109127375991488, + 0.09696383409440848, + 0.0917377571392587, + 0.0854722573661724, + 0.07823832713576369, + 0.07011793325505114, + 0.06120309065707902, + 0.051594826902497753, + 0.04140206251868274, + 0.03074049220209336, + 0.019732085056123293, + 0.008516903878747237, +]; const LEGENDRE_WEIGHT_30: [f64; 30] = [ -0.007968192496169523, -0.018466468311091087, -0.028784707883322873, -0.03879919256962679, -0.048402672830594434, -0.05749315621761909, -0.06597422988218032, -0.0737559747377048, -0.08075589522941981, -0.0868997872010827, -0.09212252223778579, -0.09636873717464399, -0.09959342058679493, -0.10176238974840521, -0.10285265289355848, -0.10285265289355848, -0.10176238974840521, -0.09959342058679493, -0.09636873717464399, -0.09212252223778579, -0.0868997872010827, -0.08075589522941981, -0.0737559747377048, -0.06597422988218032, -0.05749315621761909, -0.048402672830594434, -0.03879919256962679, -0.028784707883322873, -0.018466468311091087, -0.007968192496169523]; \ No newline at end of file + 0.007968192496169523, + 0.018466468311091087, + 0.028784707883322873, + 0.03879919256962679, + 0.048402672830594434, + 0.05749315621761909, + 0.06597422988218032, + 0.0737559747377048, + 0.08075589522941981, + 0.0868997872010827, + 0.09212252223778579, + 0.09636873717464399, + 0.09959342058679493, + 0.10176238974840521, + 0.10285265289355848, + 0.10285265289355848, + 0.10176238974840521, + 0.09959342058679493, + 0.09636873717464399, + 0.09212252223778579, + 0.0868997872010827, + 0.08075589522941981, + 0.0737559747377048, + 0.06597422988218032, + 0.05749315621761909, + 0.048402672830594434, + 0.03879919256962679, + 0.028784707883322873, + 0.018466468311091087, + 0.007968192496169523, +]; diff --git a/src/utils/helper.rs b/src/utils/helper.rs index c79089b..b88d042 100644 --- a/src/utils/helper.rs +++ b/src/utils/helper.rs @@ -2,17 +2,16 @@ use num_complex::ComplexFloat; ///utility to convert the transpose the matrix ///takes an input of a matrix of shape MxN, and returns the matrix as NxM -pub fn transpose(matrix: &[[T; NUM_COLUMNS]; NUM_ROWS]) -> [[T; NUM_ROWS]; NUM_COLUMNS] -{ +pub fn transpose( + matrix: &[[T; NUM_COLUMNS]; NUM_ROWS], +) -> [[T; NUM_ROWS]; NUM_COLUMNS] { let mut result = [[T::zero(); NUM_ROWS]; NUM_COLUMNS]; - for row_index in 0..NUM_COLUMNS - { - for col_index in 0..NUM_ROWS - { + for row_index in 0..NUM_COLUMNS { + for col_index in 0..NUM_ROWS { result[row_index][col_index] = matrix[col_index][row_index]; } } return result; -} \ No newline at end of file +} diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 80bf040..8e55c66 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -1,8 +1,8 @@ -pub mod gl_table; -pub mod gh_table; -pub mod gauss_laguerre_table; pub mod error_codes; +pub mod gauss_laguerre_table; +pub mod gh_table; +pub mod gl_table; pub mod helper; #[cfg(test)] -mod test; \ No newline at end of file +mod test; diff --git a/src/utils/test.rs b/src/utils/test.rs index 35f8f8d..d97260e 100644 --- a/src/utils/test.rs +++ b/src/utils/test.rs @@ -1,17 +1,18 @@ use crate::utils::helper; #[test] -fn test_transpose_1() -{ - let original = [[1.0, 2.0, 3.0, 4.0], [1.0, 4.0, 6.0, 8.0], [1.0, 6.0, 9.0, 12.0]]; +fn test_transpose_1() { + let original = [ + [1.0, 2.0, 3.0, 4.0], + [1.0, 4.0, 6.0, 8.0], + [1.0, 6.0, 9.0, 12.0], + ]; let trans = helper::transpose(&original); - for i in 0..original.len() - { - for j in 0..original[0].len() - { + for i in 0..original.len() { + for j in 0..original[0].len() { assert!(original[i][j] == trans[j][i]); } } -} \ No newline at end of file +} diff --git a/src/vector_field/curl.rs b/src/vector_field/curl.rs index 022a27c..7c8259e 100644 --- a/src/vector_field/curl.rs +++ b/src/vector_field/curl.rs @@ -1,44 +1,42 @@ - use crate::numerical_derivative::derivator::DerivatorMultiVariable; use num_complex::ComplexFloat; - ///solves for the curl of a 3D vector field around a given point -/// +/// /// assume a vector field, V /// V is characterized in 3 dimensions: Vx, Vy and Vz /// The curl is then defined as Cx, Cy and Cz, where: /// Cx = dVz/dy - dVy/dVz /// Cy = dVx/dz - dVz/dVx /// Cz = dVy/dx - dVx/dVy -/// +/// /// NOTE: Returns a Result /// Possible &'static str are: /// NumberOfStepsCannotBeZero -> if the derivative step size is zero -/// +/// /// Example: /// Assume we have a vector field (y, -x, 2*z) /// ``` /// use multicalc::vector_field::curl; /// use multicalc::numerical_derivative::finite_difference::*; -/// -/// let vf_x = | args: &[f64; 3] | -> f64 -/// { +/// +/// let vf_x = | args: &[f64; 3] | -> f64 +/// { /// return args[1]; /// }; /// /// //y-component -/// let vf_y = | args: &[f64; 3] | -> f64 -/// { +/// let vf_y = | args: &[f64; 3] | -> f64 +/// { /// return -args[0]; /// }; /// /// //z-component -/// let vf_z = | args: &[f64; 3] | -> f64 -/// { +/// let vf_z = | args: &[f64; 3] | -> f64 +/// { /// return 2.0*args[2]; /// }; -/// +/// /// let vector_field_matrix: [&dyn Fn(&[f64; 3]) -> f64; 3] = [&vf_x, &vf_y, &vf_z]; /// /// let point = [0.0, 1.0, 3.0]; //the point of interest @@ -50,47 +48,55 @@ use num_complex::ComplexFloat; /// assert!(f64::abs(val[1] - 0.00) < 0.00001); /// assert!(f64::abs(val[2] + 2.00) < 0.00001); /// ``` -pub fn get_3d(derivator: D, vector_field: &[&dyn Fn(&[T; NUM_VARS]) -> T; 3], point: &[T; NUM_VARS]) -> Result<[T; 3], &'static str> -where T: ComplexFloat, D: DerivatorMultiVariable +pub fn get_3d( + derivator: D, + vector_field: &[&dyn Fn(&[T; NUM_VARS]) -> T; 3], + point: &[T; NUM_VARS], +) -> Result<[T; 3], &'static str> +where + T: ComplexFloat, + D: DerivatorMultiVariable, { let mut ans = [T::zero(); 3]; - ans[0] = derivator.get(1, vector_field[2], &[1], point)? - derivator.get(1, vector_field[1], &[2], point)?; - ans[1] = derivator.get(1, vector_field[0], &[2], point)? - derivator.get(1, vector_field[2], &[0], point)?; - ans[2] = derivator.get(1, vector_field[1], &[0], point)? - derivator.get(1, vector_field[0], &[1], point)?; + ans[0] = derivator.get(1, vector_field[2], &[1], point)? + - derivator.get(1, vector_field[1], &[2], point)?; + ans[1] = derivator.get(1, vector_field[0], &[2], point)? + - derivator.get(1, vector_field[2], &[0], point)?; + ans[2] = derivator.get(1, vector_field[1], &[0], point)? + - derivator.get(1, vector_field[0], &[1], point)?; return Ok(ans); } - ///solves for the curl of a 2D vector field around a given point -/// +/// /// assume a vector field, V /// V is characterized in 3 dimensions: Vx and Vy /// The curl is then defined as dVy/dx - dVx/dVy -/// +/// /// NOTE: Returns a Result /// Possible &'static str are: /// NumberOfStepsCannotBeZero -> if the derivative step size is zero -/// +/// /// Example: /// Assume we have a vector field (2*x*y, 3*cos(y)) /// ``` /// use multicalc::vector_field::curl; /// use multicalc::numerical_derivative::finite_difference::*; -/// +/// /// //x-component -/// let vf_x = | args: &[f64; 2] | -> f64 -/// { +/// let vf_x = | args: &[f64; 2] | -> f64 +/// { /// return 2.0*args[0]*args[1]; /// }; /// /// //y-component -/// let vf_y = | args: &[f64; 2] | -> f64 -/// { +/// let vf_y = | args: &[f64; 2] | -> f64 +/// { /// return 3.0*args[1].cos() /// }; -/// +/// /// let vector_field_matrix: [&dyn Fn(&[f64; 2]) -> f64; 2] = [&vf_x, &vf_y]; /// /// let point = [1.0, 3.14]; //the point of interest @@ -100,8 +106,15 @@ where T: ComplexFloat, D: DerivatorMultiVariable /// let val = curl::get_2d(derivator, &vector_field_matrix, &point).unwrap(); /// assert!(f64::abs(val + 2.0) < 0.00001); /// ``` -pub fn get_2d(derivator: D, vector_field: &[&dyn Fn(&[T; NUM_VARS]) -> T; 2], point: &[T; NUM_VARS]) -> Result -where T: ComplexFloat, D: DerivatorMultiVariable +pub fn get_2d( + derivator: D, + vector_field: &[&dyn Fn(&[T; NUM_VARS]) -> T; 2], + point: &[T; NUM_VARS], +) -> Result +where + T: ComplexFloat, + D: DerivatorMultiVariable, { - return Ok(derivator.get(1, vector_field[1], &[0], point)? - derivator.get(1, vector_field[0], &[1], point)?); -} \ No newline at end of file + return Ok(derivator.get(1, vector_field[1], &[0], point)? + - derivator.get(1, vector_field[0], &[1], point)?); +} diff --git a/src/vector_field/divergence.rs b/src/vector_field/divergence.rs index 7e857a5..9663162 100644 --- a/src/vector_field/divergence.rs +++ b/src/vector_field/divergence.rs @@ -1,18 +1,16 @@ - use crate::numerical_derivative::derivator::DerivatorMultiVariable; use num_complex::ComplexFloat; - ///solves for the divegerence of a 3D vector field around a given point -/// +/// /// assume a vector field, V /// V is characterized in 3 dimensions: Vx, Vy and Vz /// The divergence is then defined as dVx/dx + dVy/dy + dVz/dz -/// +/// /// NOTE: Returns a Result /// Possible &'static str are: /// NumberOfStepsCannotBeZero -> if the derivative step size is zero -/// +/// /// Example: /// Assume we have a vector field (y, -x, 2*z) /// ``` @@ -20,20 +18,20 @@ use num_complex::ComplexFloat; /// use multicalc::numerical_derivative::finite_difference::*; /// /// //x-component -/// let vf_x = | args: &[f64; 3] | -> f64 -/// { +/// let vf_x = | args: &[f64; 3] | -> f64 +/// { /// return args[1]; /// }; /// /// //y-component -/// let vf_y = | args: &[f64; 3] | -> f64 -/// { +/// let vf_y = | args: &[f64; 3] | -> f64 +/// { /// return -args[0]; /// }; /// /// //z-component -/// let vf_z = | args: &[f64; 3] | -> f64 -/// { +/// let vf_z = | args: &[f64; 3] | -> f64 +/// { /// return 2.0*args[2]; /// }; /// @@ -42,44 +40,49 @@ use num_complex::ComplexFloat; /// let point = [0.0, 1.0, 3.0]; //the point of interest /// let derivator = MultiVariableSolver::default(); /// -/// //divergence known to be 2.0 +/// //divergence known to be 2.0 /// let val = divergence::get_3d(derivator, &vector_field_matrix, &point).unwrap(); /// assert!(f64::abs(val - 2.00) < 0.00001); /// ``` -pub fn get_3d(derivator: D, vector_field: &[&dyn Fn(&[T; NUM_VARS]) -> T; 3], point: &[T; NUM_VARS]) -> Result -where T: ComplexFloat, D: DerivatorMultiVariable +pub fn get_3d( + derivator: D, + vector_field: &[&dyn Fn(&[T; NUM_VARS]) -> T; 3], + point: &[T; NUM_VARS], +) -> Result +where + T: ComplexFloat, + D: DerivatorMultiVariable, { return Ok(derivator.get(1, vector_field[0], &[0], point)? - + derivator.get(1, vector_field[1], &[1], point)? - + derivator.get(1, vector_field[2], &[2], point)?); + + derivator.get(1, vector_field[1], &[1], point)? + + derivator.get(1, vector_field[2], &[2], point)?); } - ///solves for the divegerence of a 2D vector field around a given point -/// +/// /// assume a vector field, V /// V is characterized in 3 dimensions: Vx and Vy /// The divergence is then defined as dVx/dx + dVy/dy -/// +/// /// NOTE: Returns a Result /// Possible &'static str are: /// NumberOfStepsCannotBeZero -> if the derivative step size is zero -/// +/// /// Example: /// Assume we have a vector field (y, -x) /// ``` /// use multicalc::vector_field::divergence; /// use multicalc::numerical_derivative::finite_difference::*; -/// +/// /// //x-component -/// let vf_x = | args: &[f64; 2] | -> f64 -/// { +/// let vf_x = | args: &[f64; 2] | -> f64 +/// { /// return args[1]; /// }; /// /// //y-component -/// let vf_y = | args: &[f64; 2] | -> f64 -/// { +/// let vf_y = | args: &[f64; 2] | -> f64 +/// { /// return -args[0]; /// }; /// @@ -88,12 +91,19 @@ where T: ComplexFloat, D: DerivatorMultiVariable /// let point = [0.0, 1.0]; //the point of interest /// let derivator = MultiVariableSolver::default(); /// -/// //divergence known to be 0.0 +/// //divergence known to be 0.0 /// let val = divergence::get_2d(derivator, &vector_field_matrix, &point).unwrap(); /// assert!(f64::abs(val - 0.00) < 0.00001); /// ``` -pub fn get_2d(derivator: D, vector_field: &[&dyn Fn(&[T; NUM_VARS]) -> T; 2], point: &[T; NUM_VARS]) -> Result -where T: ComplexFloat, D: DerivatorMultiVariable +pub fn get_2d( + derivator: D, + vector_field: &[&dyn Fn(&[T; NUM_VARS]) -> T; 2], + point: &[T; NUM_VARS], +) -> Result +where + T: ComplexFloat, + D: DerivatorMultiVariable, { - return Ok(derivator.get(1, vector_field[0], &[0], point)? + derivator.get(1, vector_field[1], &[1], point)?); -} \ No newline at end of file + return Ok(derivator.get(1, vector_field[0], &[0], point)? + + derivator.get(1, vector_field[1], &[1], point)?); +} diff --git a/src/vector_field/flux_integral.rs b/src/vector_field/flux_integral.rs index e3aa137..845d661 100644 --- a/src/vector_field/flux_integral.rs +++ b/src/vector_field/flux_integral.rs @@ -3,25 +3,24 @@ use crate::numerical_integration::iterative_integration::DEFAULT_TOTAL_ITERATION use crate::vector_field::line_integral; use num_complex::ComplexFloat; - ///solves for the flux integral for parametrized curves in a vector field -/// +/// /// NOTE: Returns a Result /// Possible &'static str are: /// NumberOfStepsCannotBeZero -> if the number of steps argument is zero /// IntegrationLimitsIllDefined -> if the integration lower limit is not strictly lesser than the integration upper limit -/// +/// /// assume a vector field, V, and a curve, C /// V is characterized in 2 dimensions /// C is parameterized by a single variable, say, "t". /// We also need a transformation to go t->x and t->y /// The line integral limits are also based on this parameter t -/// +/// /// [vector_field] is an array of 2 elements. The 0th element has vector field's contribution to the x-axis based on x and y values. The 1st element does the same for y-axis /// [transformations] is an array of 2 elements. The 0th element contains the transformation from t->x, and 1st element for t->y /// [integration_limit] is the limit parameter 't' goes to /// [steps] is the total number of steps that the integration is discretized into. Higher number gives more accuracy, but at the cost of more computation time -/// +/// /// Example: /// Assume we have a vector field (y, -x) /// The curve is a unit circle, parameterized by (Cos(t), Sin(t)), such that t goes from 0->2*pi @@ -37,14 +36,43 @@ use num_complex::ComplexFloat; /// let val = flux_integral::get_2d(&vector_field_matrix, &transformation_matrix, &integration_limit).unwrap(); /// assert!(f64::abs(val + 0.0) < 0.01); /// ``` -pub fn get_2d(vector_field: &[&dyn Fn(&T, &T) -> T; 2], transformations: &[&dyn Fn(&T) -> T; 2], integration_limit: &[T; 2]) -> Result -{ - return Ok(line_integral::get_partial_2d(vector_field, transformations, integration_limit, DEFAULT_TOTAL_ITERATIONS, 0)? - - line_integral::get_partial_2d(vector_field, transformations, integration_limit, DEFAULT_TOTAL_ITERATIONS, 1)?); +pub fn get_2d( + vector_field: &[&dyn Fn(&T, &T) -> T; 2], + transformations: &[&dyn Fn(&T) -> T; 2], + integration_limit: &[T; 2], +) -> Result { + return Ok(line_integral::get_partial_2d( + vector_field, + transformations, + integration_limit, + DEFAULT_TOTAL_ITERATIONS, + 0, + )? - line_integral::get_partial_2d( + vector_field, + transformations, + integration_limit, + DEFAULT_TOTAL_ITERATIONS, + 1, + )?); } -pub fn get_2d_custom(vector_field: &[&dyn Fn(&T, &T) -> T; 2], transformations: &[&dyn Fn(&T) -> T; 2], integration_limit: &[T; 2], total_iterations: u64) -> Result -{ - return Ok(line_integral::get_partial_2d(vector_field, transformations, integration_limit, total_iterations, 0)? - - line_integral::get_partial_2d(vector_field, transformations, integration_limit, total_iterations, 1)?); -} \ No newline at end of file +pub fn get_2d_custom( + vector_field: &[&dyn Fn(&T, &T) -> T; 2], + transformations: &[&dyn Fn(&T) -> T; 2], + integration_limit: &[T; 2], + total_iterations: u64, +) -> Result { + return Ok(line_integral::get_partial_2d( + vector_field, + transformations, + integration_limit, + total_iterations, + 0, + )? - line_integral::get_partial_2d( + vector_field, + transformations, + integration_limit, + total_iterations, + 1, + )?); +} diff --git a/src/vector_field/line_integral.rs b/src/vector_field/line_integral.rs index 83c6a8f..a0bfe4d 100644 --- a/src/vector_field/line_integral.rs +++ b/src/vector_field/line_integral.rs @@ -4,22 +4,22 @@ use crate::numerical_integration::iterative_integration::DEFAULT_TOTAL_ITERATION use crate::utils::error_codes::*; ///solves for the line integral for parametrized curves in a 2D vector field -/// +/// /// NOTE: Returns a Result /// Possible &'static str are: /// IntegrationLimitsIllDefined -> if the integration lower limit is not strictly lesser than the integration upper limit -/// +/// /// assume a vector field, V, and a curve, C /// V is characterized in 2 dimensions, Vx and Vy /// C is parameterized by a single variable, say, "t". /// We also need a transformation to go t->x and t->y /// The line integral limits are also based on this parameter t -/// +/// /// [vector_field] is an array of 2 elements. The 0th element has vector field's contribution to the x-axis based on x and y values. The 1st element does the same for y-axis /// [transformations] is an array of 2 elements. The 0th element contains the transformation from t->x, and 1st element for t->y /// [integration_limit] is the limit parameter 't' goes to /// [steps] is the total number of steps that the integration is discretized into. Higher number gives more accuracy, but at the cost of more computation time -/// +/// /// Example: /// Assume we have a vector field (y, -x) /// The curve is a unit circle, parameterized by (Cos(t), Sin(t)), such that t goes from 0->2*pi @@ -35,37 +35,61 @@ use crate::utils::error_codes::*; /// let val = line_integral::get_2d(&vector_field_matrix, &transformation_matrix, &integration_limit).unwrap(); /// assert!(f64::abs(val + 6.28) < 0.01); /// ``` -pub fn get_2d(vector_field: &[&dyn Fn(&T, &T) -> T; 2], transformations: &[&dyn Fn(&T) -> T; 2], integration_limit: &[T; 2]) -> Result -{ - return get_2d_custom(vector_field, transformations, integration_limit, DEFAULT_TOTAL_ITERATIONS); +pub fn get_2d( + vector_field: &[&dyn Fn(&T, &T) -> T; 2], + transformations: &[&dyn Fn(&T) -> T; 2], + integration_limit: &[T; 2], +) -> Result { + return get_2d_custom( + vector_field, + transformations, + integration_limit, + DEFAULT_TOTAL_ITERATIONS, + ); } - ///same as [get_2d()] but with the option to change the total iterations used, reserved for more advanced user /// The argument 'n' denotes the number of steps to be used. However, for [`mode::IntegrationMethod::GaussLegendre`], it denotes the highest order of our equation /// NOTE: Returns a Result /// Possible &'static str are: /// NumberOfStepsCannotBeZero -> if the number of steps is zero /// IntegrationLimitsIllDefined -> if the integration lower limit is not strictly lesser than the integration upper limit -pub fn get_2d_custom(vector_field: &[&dyn Fn(&T, &T) -> T; 2], transformations: &[&dyn Fn(&T) -> T; 2], integration_limit: &[T; 2], total_iterations: u64) -> Result -{ - return Ok(get_partial_2d(vector_field, transformations, integration_limit, total_iterations, 0)? - + get_partial_2d(vector_field, transformations, integration_limit, total_iterations, 1)?); +pub fn get_2d_custom( + vector_field: &[&dyn Fn(&T, &T) -> T; 2], + transformations: &[&dyn Fn(&T) -> T; 2], + integration_limit: &[T; 2], + total_iterations: u64, +) -> Result { + return Ok(get_partial_2d( + vector_field, + transformations, + integration_limit, + total_iterations, + 0, + )? + get_partial_2d( + vector_field, + transformations, + integration_limit, + total_iterations, + 1, + )?); } - /// NOTE: Returns a Result /// Possible &'static str are: /// NumberOfStepsCannotBeZero -> if the number of steps is zero /// IntegrationLimitsIllDefined -> if the integration lower limit is not strictly lesser than the integration upper limit -pub fn get_partial_2d(vector_field: &[&dyn Fn(&T, &T) -> T; 2], transformations: &[&dyn Fn(&T) -> T; 2], integration_limit: &[T; 2], max_iterations: u64, idx: usize) -> Result -{ - if max_iterations == 0 - { +pub fn get_partial_2d( + vector_field: &[&dyn Fn(&T, &T) -> T; 2], + transformations: &[&dyn Fn(&T) -> T; 2], + integration_limit: &[T; 2], + max_iterations: u64, + idx: usize, +) -> Result { + if max_iterations == 0 { return Err(INTEGRATION_CANNOT_HAVE_ZERO_ITERATIONS); } - if integration_limit[0].abs() >= integration_limit[1].abs() - { + if integration_limit[0].abs() >= integration_limit[1].abs() { return Err(INTEGRATION_LIMITS_ILL_DEFINED); } @@ -73,15 +97,18 @@ pub fn get_partial_2d(vector_field: &[&dyn Fn(&T, &T) -> T; 2], let mut cur_point = integration_limit[0]; - let delta = (integration_limit[1] - integration_limit[0])/(T::from(max_iterations).unwrap()); + let delta = (integration_limit[1] - integration_limit[0]) / (T::from(max_iterations).unwrap()); //use the trapezoidal rule for line integrals //https://ocw.mit.edu/ans7870/18/18.013a/textbook/HTML/chapter25/section04.html - for _ in 0..max_iterations - { + for _ in 0..max_iterations { let coords = get_transformed_coordinates_2d(transformations, &cur_point, &delta); - ans = ans + (coords[idx + 2] - coords[idx])*(vector_field[idx](&coords[2], &coords[3]) + vector_field[idx](&coords[0], &coords[1]))/(T::from(2.0).unwrap()); + ans = ans + + (coords[idx + 2] - coords[idx]) + * (vector_field[idx](&coords[2], &coords[3]) + + vector_field[idx](&coords[0], &coords[1])) + / (T::from(2.0).unwrap()); cur_point = cur_point + delta; } @@ -89,43 +116,72 @@ pub fn get_partial_2d(vector_field: &[&dyn Fn(&T, &T) -> T; 2], return Ok(ans); } - ///same as [`get_2d`] but for parametrized curves in a 3D vector field /// NOTE: Returns a Result /// Possible &'static str are: /// NumberOfStepsCannotBeZero -> if the number of steps is zero /// IntegrationLimitsIllDefined -> if the integration lower limit is not strictly lesser than the integration upper limit -pub fn get_3d(vector_field: &[&dyn Fn(&T, &T, &T) -> T; 3], transformations: &[&dyn Fn(&T) -> T; 3], integration_limit: &[T; 2]) -> Result -{ - return get_3d_custom(vector_field, transformations, integration_limit, DEFAULT_TOTAL_ITERATIONS); +pub fn get_3d( + vector_field: &[&dyn Fn(&T, &T, &T) -> T; 3], + transformations: &[&dyn Fn(&T) -> T; 3], + integration_limit: &[T; 2], +) -> Result { + return get_3d_custom( + vector_field, + transformations, + integration_limit, + DEFAULT_TOTAL_ITERATIONS, + ); } - ///same as [get_3d()] but with the option to change the total iterations used, reserved for more advanced user /// The argument 'n' denotes the number of steps to be used. However, for [`mode::IntegrationMethod::GaussLegendre`], it denotes the highest order of our equation /// NOTE: Returns a Result /// Possible &'static str are: /// NumberOfStepsCannotBeZero -> if the number of steps is zero /// IntegrationLimitsIllDefined -> if the integration lower limit is not strictly lesser than the integration upper limit -pub fn get_3d_custom(vector_field: &[&dyn Fn(&T, &T, &T) -> T; 3], transformations: &[&dyn Fn(&T) -> T; 3], integration_limit: &[T; 2], total_iterations: u64) -> Result -{ - return Ok(get_partial_3d(vector_field, transformations, integration_limit, total_iterations, 0)? - + get_partial_3d(vector_field, transformations, integration_limit, total_iterations, 1)? - + get_partial_3d(vector_field, transformations, integration_limit, total_iterations, 2)?); +pub fn get_3d_custom( + vector_field: &[&dyn Fn(&T, &T, &T) -> T; 3], + transformations: &[&dyn Fn(&T) -> T; 3], + integration_limit: &[T; 2], + total_iterations: u64, +) -> Result { + return Ok(get_partial_3d( + vector_field, + transformations, + integration_limit, + total_iterations, + 0, + )? + get_partial_3d( + vector_field, + transformations, + integration_limit, + total_iterations, + 1, + )? + get_partial_3d( + vector_field, + transformations, + integration_limit, + total_iterations, + 2, + )?); } /// NOTE: Returns a Result /// Possible &'static str are: /// NumberOfStepsCannotBeZero -> if the number of steps is zero /// IntegrationLimitsIllDefined -> if the integration lower limit is not strictly lesser than the integration upper limit -pub fn get_partial_3d(vector_field: &[&dyn Fn(&T, &T, &T) -> T; 3], transformations: &[&dyn Fn(&T) -> T; 3], integration_limit: &[T; 2], steps: u64, idx: usize) -> Result -{ - if steps == 0 - { +pub fn get_partial_3d( + vector_field: &[&dyn Fn(&T, &T, &T) -> T; 3], + transformations: &[&dyn Fn(&T) -> T; 3], + integration_limit: &[T; 2], + steps: u64, + idx: usize, +) -> Result { + if steps == 0 { return Err(INTEGRATION_CANNOT_HAVE_ZERO_ITERATIONS); } - if integration_limit[0].abs() >= integration_limit[1].abs() - { + if integration_limit[0].abs() >= integration_limit[1].abs() { return Err(INTEGRATION_LIMITS_ILL_DEFINED); } @@ -133,15 +189,18 @@ pub fn get_partial_3d(vector_field: &[&dyn Fn(&T, &T, &T) -> T; let mut cur_point = integration_limit[0]; - let delta = (integration_limit[1] - integration_limit[0])/(T::from(steps).unwrap()); + let delta = (integration_limit[1] - integration_limit[0]) / (T::from(steps).unwrap()); //use the trapezoidal rule for line integrals //https://ocw.mit.edu/ans7870/18/18.013a/textbook/HTML/chapter25/section04.html - for _ in 0..steps - { + for _ in 0..steps { let coords = get_transformed_coordinates_3d(transformations, &cur_point, &delta); - ans = ans + (coords[idx + 3] - coords[idx])*(vector_field[idx](&coords[3], &coords[4], &coords[5]) + vector_field[idx](&coords[0], &coords[1], &coords[2]))/(T::from(2.0).unwrap()); + ans = ans + + (coords[idx + 3] - coords[idx]) + * (vector_field[idx](&coords[3], &coords[4], &coords[5]) + + vector_field[idx](&coords[0], &coords[1], &coords[2])) + / (T::from(2.0).unwrap()); cur_point = cur_point + delta; } @@ -149,11 +208,11 @@ pub fn get_partial_3d(vector_field: &[&dyn Fn(&T, &T, &T) -> T; return Ok(ans); } - - - -fn get_transformed_coordinates_2d(transformations: &[&dyn Fn(&T) -> T; 2], cur_point: &T, delta: &T) -> [T; 4] -{ +fn get_transformed_coordinates_2d( + transformations: &[&dyn Fn(&T) -> T; 2], + cur_point: &T, + delta: &T, +) -> [T; 4] { let mut ans = [T::zero(); 4]; ans[0] = transformations[0](cur_point); //x at t @@ -165,9 +224,11 @@ fn get_transformed_coordinates_2d(transformations: &[&dyn Fn(&T return ans; } - -fn get_transformed_coordinates_3d(transformations: &[&dyn Fn(&T) -> T; 3], cur_point: &T, delta: &T) -> [T; 6] -{ +fn get_transformed_coordinates_3d( + transformations: &[&dyn Fn(&T) -> T; 3], + cur_point: &T, + delta: &T, +) -> [T; 6] { let mut ans = [T::zero(); 6]; ans[0] = transformations[0](cur_point); //x at t @@ -179,4 +240,4 @@ fn get_transformed_coordinates_3d(transformations: &[&dyn Fn(&T ans[5] = transformations[1](&(*cur_point + *delta)); //z at t + delta return ans; -} \ No newline at end of file +} diff --git a/src/vector_field/mod.rs b/src/vector_field/mod.rs index 7782d0c..40770c9 100644 --- a/src/vector_field/mod.rs +++ b/src/vector_field/mod.rs @@ -1,8 +1,7 @@ -pub mod line_integral; -pub mod flux_integral; pub mod curl; pub mod divergence; - +pub mod flux_integral; +pub mod line_integral; #[cfg(test)] -mod test; \ No newline at end of file +mod test; diff --git a/src/vector_field/test.rs b/src/vector_field/test.rs index b7e5b4a..5d49b63 100644 --- a/src/vector_field/test.rs +++ b/src/vector_field/test.rs @@ -1,104 +1,140 @@ use crate::numerical_derivative::finite_difference::MultiVariableSolver; +use crate::vector_field::curl; use crate::vector_field::divergence; -use crate::vector_field::line_integral; use crate::vector_field::flux_integral; -use crate::vector_field::curl; +use crate::vector_field::line_integral; use crate::utils::error_codes::*; #[test] -fn test_line_integral_1() -{ +fn test_line_integral_1() { //vector field is (y, -x) //curve is a unit circle, defined by (Cos(t), Sin(t)) //limit t goes from 0->2*pi - let vector_field_matrix: [&dyn Fn(&f64, &f64) -> f64; 2] = [&(|_:&f64, y:&f64|-> f64 { *y }), &(|x:&f64, _:&f64|-> f64 { -x })]; + let vector_field_matrix: [&dyn Fn(&f64, &f64) -> f64; 2] = [ + &(|_: &f64, y: &f64| -> f64 { *y }), + &(|x: &f64, _: &f64| -> f64 { -x }), + ]; - let transformation_matrix: [&dyn Fn(&f64) -> f64; 2] = [&(|t:&f64|->f64 { t.cos() }), &(|t:&f64|->f64 { t.sin() })]; + let transformation_matrix: [&dyn Fn(&f64) -> f64; 2] = [ + &(|t: &f64| -> f64 { t.cos() }), + &(|t: &f64| -> f64 { t.sin() }), + ]; let integration_limit = [0.0, 6.28]; //line integral of a unit circle curve on our vector field from 0 to 2*pi, expect an answer of -2.0*pi - let val = line_integral::get_2d_custom(&vector_field_matrix, &transformation_matrix, &integration_limit, 100).unwrap(); + let val = line_integral::get_2d_custom( + &vector_field_matrix, + &transformation_matrix, + &integration_limit, + 100, + ) + .unwrap(); assert!(f64::abs(val + 6.28) < 0.01); } #[test] -fn test_line_integral_error_1() -{ +fn test_line_integral_error_1() { //vector field is (y, -x) //curve is a unit circle, defined by (Cos(t), Sin(t)) //limit t goes from 0->2*pi - let vector_field_matrix: [&dyn Fn(&f64, &f64) -> f64; 2] = [&(|_:&f64, y:&f64|-> f64 { *y }), &(|x:&f64, _:&f64|-> f64 { -x })]; + let vector_field_matrix: [&dyn Fn(&f64, &f64) -> f64; 2] = [ + &(|_: &f64, y: &f64| -> f64 { *y }), + &(|x: &f64, _: &f64| -> f64 { -x }), + ]; - let transformation_matrix: [&dyn Fn(&f64) -> f64; 2] = [&(|t:&f64|->f64 { t.cos() }), &(|t:&f64|->f64 { t.sin() })]; + let transformation_matrix: [&dyn Fn(&f64) -> f64; 2] = [ + &(|t: &f64| -> f64 { t.cos() }), + &(|t: &f64| -> f64 { t.sin() }), + ]; let integration_limit = [0.0, 6.28]; //expect error because number of steps is zero - let val = line_integral::get_2d_custom(&vector_field_matrix, &transformation_matrix, &integration_limit, 0); + let val = line_integral::get_2d_custom( + &vector_field_matrix, + &transformation_matrix, + &integration_limit, + 0, + ); assert!(val.is_err()); assert!(val.unwrap_err() == INTEGRATION_CANNOT_HAVE_ZERO_ITERATIONS); } #[test] -fn test_line_integral_error_2() -{ +fn test_line_integral_error_2() { //vector field is (y, -x) //curve is a unit circle, defined by (Cos(t), Sin(t)) //limit t goes from 0->2*pi - let vector_field_matrix: [&dyn Fn(&f64, &f64) -> f64; 2] = [&(|_:&f64, y:&f64|-> f64 { *y }), &(|x:&f64, _:&f64|-> f64 { -x })]; + let vector_field_matrix: [&dyn Fn(&f64, &f64) -> f64; 2] = [ + &(|_: &f64, y: &f64| -> f64 { *y }), + &(|x: &f64, _: &f64| -> f64 { -x }), + ]; - let transformation_matrix: [&dyn Fn(&f64) -> f64; 2] = [&(|t:&f64|->f64 { t.cos() }), &(|t:&f64|->f64 { t.sin() })]; + let transformation_matrix: [&dyn Fn(&f64) -> f64; 2] = [ + &(|t: &f64| -> f64 { t.cos() }), + &(|t: &f64| -> f64 { t.sin() }), + ]; let integration_limit = [10.0, 0.0]; //expect error because integration limits are ill-defined (lower limit higher than upper limit) - let val = line_integral::get_2d_custom(&vector_field_matrix, &transformation_matrix, &integration_limit, 100); + let val = line_integral::get_2d_custom( + &vector_field_matrix, + &transformation_matrix, + &integration_limit, + 100, + ); assert!(val.is_err()); assert!(val.unwrap_err() == INTEGRATION_LIMITS_ILL_DEFINED); } - #[test] -fn test_flux_integral_1() -{ +fn test_flux_integral_1() { //vector field is (y, -x) //curve is a unit circle, defined by (Cos(t), Sin(t)) //limit t goes from 0->2*pi - let vector_field_matrix: [&dyn Fn(&f64, &f64) -> f64; 2] = [&(|_:&f64, y:&f64|-> f64 { *y }), &(|x:&f64, _:&f64|-> f64 { -x })]; + let vector_field_matrix: [&dyn Fn(&f64, &f64) -> f64; 2] = [ + &(|_: &f64, y: &f64| -> f64 { *y }), + &(|x: &f64, _: &f64| -> f64 { -x }), + ]; - let transformation_matrix: [&dyn Fn(&f64) -> f64; 2] = [&(|t:&f64|->f64 { t.cos() }), &(|t:&f64|->f64 { t.sin() })]; + let transformation_matrix: [&dyn Fn(&f64) -> f64; 2] = [ + &(|t: &f64| -> f64 { t.cos() }), + &(|t: &f64| -> f64 { t.sin() }), + ]; let integration_limit = [0.0, 6.28]; //flux integral of a unit circle curve on our vector field from 0 to 2*pi, expect an answer of 0.0 - let val = flux_integral::get_2d_custom(&vector_field_matrix, &transformation_matrix, &integration_limit, 100).unwrap(); + let val = flux_integral::get_2d_custom( + &vector_field_matrix, + &transformation_matrix, + &integration_limit, + 100, + ) + .unwrap(); assert!(f64::abs(val + 0.0) < 0.01); } #[test] -fn test_curl_2d_1() -{ +fn test_curl_2d_1() { //vector field is (2*x*y, 3*cos(y)) //x-component - let vf_x = | args: &[f64; 2] | -> f64 - { - return 2.0*args[0]*args[1]; + let vf_x = |args: &[f64; 2]| -> f64 { + return 2.0 * args[0] * args[1]; }; //y-component - let vf_y = | args: &[f64; 2] | -> f64 - { - return 3.0*args[1].cos() - }; - + let vf_y = |args: &[f64; 2]| -> f64 { return 3.0 * args[1].cos() }; + let vector_field_matrix: [&dyn Fn(&[f64; 2]) -> f64; 2] = [&vf_x, &vf_y]; let point = [1.0, 3.14]; @@ -111,25 +147,21 @@ fn test_curl_2d_1() } #[test] -fn test_curl_3d_1() -{ +fn test_curl_3d_1() { //vector field is (y, -x, 2*z) //x-component - let vf_x = | args: &[f64; 3] | -> f64 - { + let vf_x = |args: &[f64; 3]| -> f64 { return args[1]; }; //y-component - let vf_y = | args: &[f64; 3] | -> f64 - { + let vf_y = |args: &[f64; 3]| -> f64 { return -args[0]; }; //z-component - let vf_z = | args: &[f64; 3] | -> f64 - { - return 2.0*args[2]; + let vf_z = |args: &[f64; 3]| -> f64 { + return 2.0 * args[2]; }; let vector_field_matrix: [&dyn Fn(&[f64; 3]) -> f64; 3] = [&vf_x, &vf_y, &vf_z]; @@ -146,21 +178,16 @@ fn test_curl_3d_1() } #[test] -fn test_divergence_2d_1() -{ +fn test_divergence_2d_1() { //vector field is (2*x*y, 3*cos(y)) //x-component - let vf_x = | args: &[f64; 2] | -> f64 - { - return 2.0*args[0]*args[1]; + let vf_x = |args: &[f64; 2]| -> f64 { + return 2.0 * args[0] * args[1]; }; //y-component - let vf_y = | args: &[f64; 2] | -> f64 - { - return 3.0*args[1].cos() - }; - + let vf_y = |args: &[f64; 2]| -> f64 { return 3.0 * args[1].cos() }; + let vector_field_matrix: [&dyn Fn(&[f64; 2]) -> f64; 2] = [&vf_x, &vf_y]; let point = [1.0, 3.14]; @@ -172,25 +199,21 @@ fn test_divergence_2d_1() } #[test] -fn test_divergence_3d_1() -{ +fn test_divergence_3d_1() { //vector field is (y, -x, 2*z) //x-component - let vf_x = | args: &[f64; 3] | -> f64 - { + let vf_x = |args: &[f64; 3]| -> f64 { return args[1]; }; //y-component - let vf_y = | args: &[f64; 3] | -> f64 - { + let vf_y = |args: &[f64; 3]| -> f64 { return -args[0]; }; //z-component - let vf_z = | args: &[f64; 3] | -> f64 - { - return 2.0*args[2]; + let vf_z = |args: &[f64; 3]| -> f64 { + return 2.0 * args[2]; }; let vector_field_matrix: [&dyn Fn(&[f64; 3]) -> f64; 3] = [&vf_x, &vf_y, &vf_z]; @@ -198,7 +221,7 @@ fn test_divergence_3d_1() let derivator = MultiVariableSolver::default(); - //diverge known to be 2.0 + //diverge known to be 2.0 let val = divergence::get_3d(derivator, &vector_field_matrix, &point).unwrap(); assert!(f64::abs(val - 2.00) < 0.00001); -} \ No newline at end of file +}