use crate::numerical_integration::iterative_integration::DEFAULT_TOTAL_ITERATIONS;
use crate::scalar::Numeric;
use crate::utils::error_codes::CalcError;
fn curve_point<T: Numeric, const N: usize>(transformations: &[&dyn Fn(T) -> T; N], t: T) -> [T; N] {
let mut point = [T::ZERO; N];
for i in 0..N {
point[i] = transformations[i](t);
}
point
}
fn get_partial<T: Numeric, const N: usize>(
vector_field: &[&dyn Fn(&[T; N]) -> T; N],
transformations: &[&dyn Fn(T) -> T; N],
integration_limit: &[T; 2],
total_iterations: u64,
idx: usize,
) -> Result<T, CalcError> {
if total_iterations == 0 {
return Err(CalcError::IterationsZero);
}
if !matches!(
integration_limit[0].partial_cmp(&integration_limit[1]),
Some(core::cmp::Ordering::Less)
) {
return Err(CalcError::IntegrationLimitsIllDefined);
}
let delta = (integration_limit[1] - integration_limit[0]) / T::from_u64(total_iterations);
let mut t = integration_limit[0];
let mut ans = T::ZERO;
let mut left = curve_point(transformations, t);
let mut left_value = vector_field[idx](&left);
for _ in 0..total_iterations {
let right = curve_point(transformations, t + delta);
let right_value = vector_field[idx](&right);
ans += (right[idx] - left[idx]) * (left_value + right_value) / T::TWO;
t += delta;
left = right;
left_value = right_value;
}
Ok(ans)
}
pub fn get_2d<T: Numeric>(
vector_field: &[&dyn Fn(&[T; 2]) -> T; 2],
transformations: &[&dyn Fn(T) -> T; 2],
integration_limit: &[T; 2],
) -> Result<T, CalcError> {
get_2d_custom(
vector_field,
transformations,
integration_limit,
DEFAULT_TOTAL_ITERATIONS,
)
}
pub fn get_2d_custom<T: Numeric>(
vector_field: &[&dyn Fn(&[T; 2]) -> T; 2],
transformations: &[&dyn Fn(T) -> T; 2],
integration_limit: &[T; 2],
total_iterations: u64,
) -> Result<T, CalcError> {
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: Numeric>(
vector_field: &[&dyn Fn(&[T; 2]) -> T; 2],
transformations: &[&dyn Fn(T) -> T; 2],
integration_limit: &[T; 2],
total_iterations: u64,
idx: usize,
) -> Result<T, CalcError> {
get_partial(
vector_field,
transformations,
integration_limit,
total_iterations,
idx,
)
}
pub fn get_3d<T: Numeric>(
vector_field: &[&dyn Fn(&[T; 3]) -> T; 3],
transformations: &[&dyn Fn(T) -> T; 3],
integration_limit: &[T; 2],
) -> Result<T, CalcError> {
get_3d_custom(
vector_field,
transformations,
integration_limit,
DEFAULT_TOTAL_ITERATIONS,
)
}
pub fn get_3d_custom<T: Numeric>(
vector_field: &[&dyn Fn(&[T; 3]) -> T; 3],
transformations: &[&dyn Fn(T) -> T; 3],
integration_limit: &[T; 2],
total_iterations: u64,
) -> Result<T, CalcError> {
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: Numeric>(
vector_field: &[&dyn Fn(&[T; 3]) -> T; 3],
transformations: &[&dyn Fn(T) -> T; 3],
integration_limit: &[T; 2],
total_iterations: u64,
idx: usize,
) -> Result<T, CalcError> {
get_partial(
vector_field,
transformations,
integration_limit,
total_iterations,
idx,
)
}