use crate::numerical_integration::integrator::*;
use crate::numerical_integration::mode::IterativeMethod;
use crate::utils::error_codes::*;
pub const DEFAULT_TOTAL_ITERATIONS: u64 = 100;
#[derive(Clone, Copy)]
pub struct SingleVariableSolver
{
total_iterations: u64,
integration_method: IterativeMethod
}
impl Default for SingleVariableSolver
{
fn default() -> Self
{
return SingleVariableSolver { total_iterations: DEFAULT_TOTAL_ITERATIONS, integration_method: IterativeMethod::Booles };
}
}
impl SingleVariableSolver
{
pub fn get_total_iterations(&self) -> u64
{
return self.total_iterations;
}
pub fn set_total_iterations(&mut self, total_iterations: u64)
{
self.total_iterations = total_iterations;
}
pub fn get_integration_method(&self) -> IterativeMethod
{
return self.integration_method;
}
pub fn set_integration_method(&mut self, integration_method: IterativeMethod)
{
self.integration_method = integration_method;
}
pub fn from_parameters(total_iterations: u64, integration_method: IterativeMethod) -> Self
{
SingleVariableSolver
{
total_iterations: total_iterations,
integration_method: integration_method
}
}
fn check_for_errors<const NUM_INTEGRATIONS: usize>(&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]
{
return Err(INTEGRATION_LIMITS_ILL_DEFINED);
}
}
if NUM_INTEGRATIONS != number_of_integrations
{
return Err(INCORRECT_NUMBER_OF_INTEGRATION_LIMITS)
}
return Ok(());
}
fn get_booles<const NUM_INTEGRATIONS: usize>(&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 multiplier = 32.0;
for iter in 0..self.total_iterations-1
{
current_point = current_point + delta;
ans = ans + multiplier*func(current_point);
if (iter + 2) % 2 != 0
{
multiplier = 32.0;
}
else if (iter + 2) % 4 == 0
{
multiplier = 14.0;
}
else
{
multiplier = 12.0;
}
}
current_point = integration_limit[0][1];
ans = ans + 7.0*func(current_point);
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 multiplier = 32.0;
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
{
multiplier = 32.0;
}
else if (iter + 2) % 4 == 0
{
multiplier = 14.0;
}
else
{
multiplier = 12.0
}
}
ans = ans + 7.0*self.get_booles(number_of_integrations - 1, func, integration_limit);
return 2.0*delta*ans/45.0;
}
fn get_simpsons<const NUM_INTEGRATIONS: usize>(&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 mut multiplier = 3.0;
for iter in 0..self.total_iterations-1
{
current_point = current_point + delta;
ans = ans + multiplier*func(current_point);
if (iter + 2) % 3 == 0
{
multiplier = 2.0;
}
else
{
multiplier = 3.0;
}
}
current_point = integration_limit[0][1];
ans = ans + func(current_point);
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 mut multiplier = 3.0;
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);
if (iter + 2) % 3 == 0
{
multiplier = 2.0;
}
else
{
multiplier = 3.0;
}
}
ans = ans + self.get_simpsons(number_of_integrations - 1, func, integration_limit);
return 3.0*delta*ans/8.0;
}
fn get_trapezoidal<const NUM_INTEGRATIONS: usize>(&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);
for _ in 0..self.total_iterations-1
{
current_point = current_point + delta;
ans = ans + 2.0*func(current_point);
}
current_point = integration_limit[0][1];
ans = ans + func(current_point);
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);
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 + self.get_trapezoidal(number_of_integrations - 1, func, integration_limit);
return 0.5*delta*ans;
}
}
impl IntegratorSingleVariable for SingleVariableSolver
{
fn get<const NUM_INTEGRATIONS: usize>(&self, number_of_integrations: usize, func: &dyn Fn(f64) -> f64, integration_limit: &[[f64; 2]; NUM_INTEGRATIONS]) -> Result<f64, &'static str>
{
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))
}
}
}
#[derive(Clone, Copy)]
pub struct MultiVariableSolver
{
total_iterations: u64,
integration_method: IterativeMethod
}
impl Default for MultiVariableSolver
{
fn default() -> Self
{
return MultiVariableSolver { total_iterations: DEFAULT_TOTAL_ITERATIONS, integration_method: IterativeMethod::Booles };
}
}
impl MultiVariableSolver
{
pub fn get_total_iterations(&self) -> u64
{
return self.total_iterations;
}
pub fn set_total_iterations(&mut self, total_iterations: u64)
{
self.total_iterations = total_iterations;
}
pub fn get_integration_method(&self) -> IterativeMethod
{
return self.integration_method;
}
pub fn set_integration_method(&mut self, integration_method: IterativeMethod)
{
self.integration_method = integration_method;
}
pub fn from_parameters(total_iterations: u64, integration_method: IterativeMethod) -> Self
{
MultiVariableSolver
{
total_iterations: total_iterations,
integration_method: integration_method
}
}
fn check_for_errors<const NUM_INTEGRATIONS: usize>(&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]
{
return Err(INTEGRATION_LIMITS_ILL_DEFINED);
}
}
if NUM_INTEGRATIONS != number_of_integrations
{
return Err(INCORRECT_NUMBER_OF_INTEGRATION_LIMITS)
}
return Ok(());
}
fn get_booles<const NUM_VARS: usize, const NUM_INTEGRATIONS: usize>(&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 multiplier = 32.0;
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
{
multiplier = 32.0;
}
else if (iter + 2) % 4 == 0
{
multiplier = 14.0;
}
else
{
multiplier = 12.0;
}
}
current_vec[idx_to_integrate[0]] = integration_limits[0][1];
ans = ans + 7.0*func(¤t_vec);
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);
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
{
multiplier = 32.0;
}
else if (iter + 2) % 4 == 0
{
multiplier = 14.0;
}
else
{
multiplier = 12.0;
}
}
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);
return 2.0*delta*ans/45.0;
}
fn get_simpsons<const NUM_VARS: usize, const NUM_INTEGRATIONS: usize>(&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 mut multiplier = 3.0;
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) % 3 == 0
{
multiplier = 2.0;
}
else
{
multiplier = 3.0;
}
}
current_vec[idx_to_integrate[0]] = integration_limits[0][1];
ans = ans + func(¤t_vec);
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);
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
{
multiplier = 2.0;
}
else
{
multiplier = 3.0;
}
}
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);
return 3.0*delta*ans/8.0;
}
fn get_trapezoidal<const NUM_VARS: usize, const NUM_INTEGRATIONS: usize>(&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);
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);
}
current_vec[idx_to_integrate[0]] = integration_limits[0][1];
ans = ans + func(¤t_vec);
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][1];
ans = ans + self.get_trapezoidal(number_of_integrations-1, idx_to_integrate, func, integration_limits, ¤t_vec);
return 0.5*delta*ans;
}
}
impl IntegratorMultiVariable for MultiVariableSolver
{
fn get<const NUM_VARS: usize, const NUM_INTEGRATIONS: usize>(&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<f64, &'static str>
{
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))
}
}
}