use num_complex::ComplexFloat;
use crate::numerical_integration::iterative_integration::DEFAULT_TOTAL_ITERATIONS;
use crate::utils::error_codes::*;
pub fn get_2d<T: ComplexFloat>(vector_field: &[&dyn Fn(&T, &T) -> T; 2], transformations: &[&dyn Fn(&T) -> T; 2], integration_limit: &[T; 2]) -> Result<T, &'static str>
{
return get_2d_custom(vector_field, transformations, integration_limit, DEFAULT_TOTAL_ITERATIONS);
}
pub fn get_2d_custom<T: ComplexFloat>(vector_field: &[&dyn Fn(&T, &T) -> T; 2], transformations: &[&dyn Fn(&T) -> T; 2], integration_limit: &[T; 2], total_iterations: u64) -> Result<T, &'static str>
{
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_partial_2d<T: ComplexFloat>(vector_field: &[&dyn Fn(&T, &T) -> T; 2], transformations: &[&dyn Fn(&T) -> T; 2], integration_limit: &[T; 2], max_iterations: u64, idx: usize) -> Result<T, &'static str>
{
if max_iterations == 0
{
return Err(INTEGRATION_CANNOT_HAVE_ZERO_ITERATIONS);
}
if integration_limit[0].abs() >= integration_limit[1].abs()
{
return Err(INTEGRATION_LIMITS_ILL_DEFINED);
}
let mut ans = T::zero();
let mut cur_point = integration_limit[0];
let delta = (integration_limit[1] - integration_limit[0])/(T::from(max_iterations).unwrap());
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());
cur_point = cur_point + delta;
}
return Ok(ans);
}
pub fn get_3d<T: ComplexFloat>(vector_field: &[&dyn Fn(&T, &T, &T) -> T; 3], transformations: &[&dyn Fn(&T) -> T; 3], integration_limit: &[T; 2]) -> Result<T, &'static str>
{
return get_3d_custom(vector_field, transformations, integration_limit, DEFAULT_TOTAL_ITERATIONS);
}
pub fn get_3d_custom<T: ComplexFloat>(vector_field: &[&dyn Fn(&T, &T, &T) -> T; 3], transformations: &[&dyn Fn(&T) -> T; 3], integration_limit: &[T; 2], total_iterations: u64) -> Result<T, &'static str>
{
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_partial_3d<T: ComplexFloat>(vector_field: &[&dyn Fn(&T, &T, &T) -> T; 3], transformations: &[&dyn Fn(&T) -> T; 3], integration_limit: &[T; 2], steps: u64, idx: usize) -> Result<T, &'static str>
{
if steps == 0
{
return Err(INTEGRATION_CANNOT_HAVE_ZERO_ITERATIONS);
}
if integration_limit[0].abs() >= integration_limit[1].abs()
{
return Err(INTEGRATION_LIMITS_ILL_DEFINED);
}
let mut ans = T::zero();
let mut cur_point = integration_limit[0];
let delta = (integration_limit[1] - integration_limit[0])/(T::from(steps).unwrap());
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());
cur_point = cur_point + delta;
}
return Ok(ans);
}
fn get_transformed_coordinates_2d<T: ComplexFloat>(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); ans[1] = transformations[1](cur_point);
ans[2] = transformations[0](&(*cur_point + *delta)); ans[3] = transformations[1](&(*cur_point + *delta));
return ans;
}
fn get_transformed_coordinates_3d<T: ComplexFloat>(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); ans[1] = transformations[1](cur_point); ans[2] = transformations[1](cur_point);
ans[3] = transformations[0](&(*cur_point + *delta)); ans[4] = transformations[1](&(*cur_point + *delta)); ans[5] = transformations[1](&(*cur_point + *delta));
return ans;
}