use scirs2_core::ndarray::Array1;
use scirs2_core::numeric::{Float, FromPrimitive};
use std::default::Default;
use std::ops::AddAssign;
use super::advanced::AdvancedExtrapolator;
use super::config::{
AdaptiveExtrapolationConfig, AutoregressiveExtrapolationConfig, ConfidenceExtrapolationConfig,
EnsembleExtrapolationConfig, ExtrapolationParameters,
};
use super::core::Extrapolator;
use super::types::{
ARFittingMethod, AdaptiveSelectionCriterion, EnsembleCombinationStrategy, ExtrapolationMethod,
};
pub fn make_linear_extrapolator<T: Float + std::fmt::Display>(
lower_bound: T,
upper_bound: T,
lower_value: T,
upper_value: T,
lower_derivative: T,
upper_derivative: T,
) -> Extrapolator<T> {
Extrapolator::new(
lower_bound,
upper_bound,
lower_value,
upper_value,
ExtrapolationMethod::Linear,
ExtrapolationMethod::Linear,
)
.with_derivatives(lower_derivative, upper_derivative)
}
pub fn make_periodic_extrapolator<T: Float + std::fmt::Display>(
lower_bound: T,
upper_bound: T,
period: Option<T>,
) -> Extrapolator<T> {
let mut extrapolator = Extrapolator::new(
lower_bound,
upper_bound,
T::zero(), T::zero(),
ExtrapolationMethod::Periodic,
ExtrapolationMethod::Periodic,
);
if let Some(p) = period {
let params = ExtrapolationParameters::default().with_period(p);
extrapolator = extrapolator.with_parameters(params);
}
extrapolator
}
pub fn make_reflection_extrapolator<T: Float + std::fmt::Display>(
lower_bound: T,
upper_bound: T,
) -> Extrapolator<T> {
Extrapolator::new(
lower_bound,
upper_bound,
T::zero(), T::zero(),
ExtrapolationMethod::Reflection,
ExtrapolationMethod::Reflection,
)
}
#[allow(clippy::too_many_arguments)]
pub fn make_cubic_extrapolator<T: Float + std::fmt::Display>(
lower_bound: T,
upper_bound: T,
lower_value: T,
upper_value: T,
lower_derivative: T,
upper_derivative: T,
lower_second_derivative: T,
upper_second_derivative: T,
) -> Extrapolator<T> {
Extrapolator::new(
lower_bound,
upper_bound,
lower_value,
upper_value,
ExtrapolationMethod::Cubic,
ExtrapolationMethod::Cubic,
)
.with_derivatives(lower_derivative, upper_derivative)
.with_second_derivatives(lower_second_derivative, upper_second_derivative)
}
#[allow(clippy::too_many_arguments)]
pub fn make_exponential_extrapolator<T: Float + std::fmt::Display>(
lower_bound: T,
upper_bound: T,
lower_value: T,
upper_value: T,
lower_derivative: T,
upper_derivative: T,
exponential_rate: T,
exponential_offset: T,
) -> Extrapolator<T> {
let params = ExtrapolationParameters::default()
.with_exponential_rate(exponential_rate)
.with_exponential_offset(exponential_offset);
Extrapolator::new(
lower_bound,
upper_bound,
lower_value,
upper_value,
ExtrapolationMethod::Exponential,
ExtrapolationMethod::Exponential,
)
.with_derivatives(lower_derivative, upper_derivative)
.with_parameters(params)
}
#[allow(clippy::too_many_arguments)]
pub fn make_power_law_extrapolator<T: Float + std::fmt::Display>(
lower_bound: T,
upper_bound: T,
lower_value: T,
upper_value: T,
lower_derivative: T,
upper_derivative: T,
power_exponent: T,
power_scale: T,
) -> Extrapolator<T> {
let params = ExtrapolationParameters::default()
.with_power_exponent(power_exponent)
.with_power_scale(power_scale);
Extrapolator::new(
lower_bound,
upper_bound,
lower_value,
upper_value,
ExtrapolationMethod::PowerLaw,
ExtrapolationMethod::PowerLaw,
)
.with_derivatives(lower_derivative, upper_derivative)
.with_parameters(params)
}
pub fn make_zeros_extrapolator<T: Float + std::fmt::Display>(
lower_bound: T,
upper_bound: T,
) -> Extrapolator<T> {
Extrapolator::new(
lower_bound,
upper_bound,
T::zero(),
T::zero(),
ExtrapolationMethod::Zeros,
ExtrapolationMethod::Zeros,
)
}
pub fn make_nearest_extrapolator<T: Float + std::fmt::Display>(
lower_bound: T,
upper_bound: T,
lower_value: T,
upper_value: T,
) -> Extrapolator<T> {
Extrapolator::new(
lower_bound,
upper_bound,
lower_value,
upper_value,
ExtrapolationMethod::Nearest,
ExtrapolationMethod::Nearest,
)
}
pub fn make_confidence_extrapolator<T: Float + std::fmt::Display + Default + AddAssign>(
base_extrapolator: Extrapolator<T>,
confidence_level: T,
bootstrap_samples: usize,
) -> AdvancedExtrapolator<T> {
let config = ConfidenceExtrapolationConfig {
bootstrap_samples,
confidence_level,
max_extrapolation_ratio: T::from(0.5).expect("Operation failed"),
bias_correction: true,
};
AdvancedExtrapolator::new(base_extrapolator).with_confidence(config)
}
pub fn make_ensemble_extrapolator<T: Float + std::fmt::Display + Default + AddAssign>(
base_extrapolator: Extrapolator<T>,
methods: Vec<ExtrapolationMethod>,
weights: Option<Vec<T>>,
strategy: EnsembleCombinationStrategy,
) -> AdvancedExtrapolator<T> {
let config = EnsembleExtrapolationConfig {
methods,
combination_strategy: strategy,
weights,
include_confidence: true,
};
AdvancedExtrapolator::new(base_extrapolator).with_ensemble(config)
}
pub fn make_adaptive_extrapolator<T: Float + std::fmt::Display + Default + AddAssign>(
base_extrapolator: Extrapolator<T>,
selection_criterion: AdaptiveSelectionCriterion,
local_window_size: usize,
minimum_confidence: f64,
) -> AdvancedExtrapolator<T> {
let config = AdaptiveExtrapolationConfig {
selection_criterion,
local_window_size,
minimum_confidence,
cache_selections: true,
};
AdvancedExtrapolator::new(base_extrapolator).with_adaptive(config)
}
pub fn make_autoregressive_extrapolator<T: Float + std::fmt::Display + Default + AddAssign>(
base_extrapolator: Extrapolator<T>,
ar_order: usize,
fitting_method: ARFittingMethod,
historical_data: Option<(Array1<T>, Array1<T>)>,
) -> AdvancedExtrapolator<T> {
let config = AutoregressiveExtrapolationConfig {
ar_order,
fitting_method,
max_steps: 100,
trend_adjustment: true,
regularization: T::from(1e-6).unwrap_or(T::zero()),
};
let mut extrapolator = AdvancedExtrapolator::new(base_extrapolator).with_autoregressive(config);
if let Some((x_data, y_data)) = historical_data {
extrapolator = extrapolator.with_historical_data(x_data, y_data);
}
extrapolator
}
pub fn make_conservative_extrapolator<T: Float + std::fmt::Display>(
lower_bound: T,
upper_bound: T,
lower_value: T,
upper_value: T,
lower_derivative: T,
upper_derivative: T,
max_extrapolation_distance: T,
) -> Extrapolator<T> {
let _ = max_extrapolation_distance;
make_linear_extrapolator(
lower_bound,
upper_bound,
lower_value,
upper_value,
lower_derivative,
upper_derivative,
)
}
pub fn make_robust_ensemble_extrapolator<T: Float + std::fmt::Display + Default + AddAssign>(
lower_bound: T,
upper_bound: T,
lower_value: T,
upper_value: T,
lower_derivative: T,
upper_derivative: T,
) -> AdvancedExtrapolator<T> {
let base_extrapolator = make_linear_extrapolator(
lower_bound,
upper_bound,
lower_value,
upper_value,
lower_derivative,
upper_derivative,
);
let methods = vec![
ExtrapolationMethod::Linear,
ExtrapolationMethod::Quadratic,
ExtrapolationMethod::Exponential,
];
let weights = Some(vec![
T::from(0.5).expect("Operation failed"), T::from(0.3).expect("Operation failed"), T::from(0.2).expect("Operation failed"), ]);
make_ensemble_extrapolator(
base_extrapolator,
methods,
weights,
EnsembleCombinationStrategy::WeightedMean,
)
}
pub fn make_smooth_function_extrapolator<T: Float + std::fmt::Display>(
lower_bound: T,
upper_bound: T,
lower_value: T,
upper_value: T,
lower_derivative: T,
upper_derivative: T,
lower_second_derivative: T,
upper_second_derivative: T,
) -> Extrapolator<T> {
make_cubic_extrapolator(
lower_bound,
upper_bound,
lower_value,
upper_value,
lower_derivative,
upper_derivative,
lower_second_derivative,
upper_second_derivative,
)
}
pub fn make_oscillatory_extrapolator<T: Float + std::fmt::Display>(
lower_bound: T,
upper_bound: T,
period: Option<T>,
) -> Extrapolator<T> {
make_periodic_extrapolator(lower_bound, upper_bound, period)
}
pub fn make_monotonic_extrapolator<T: Float + std::fmt::Display>(
lower_bound: T,
upper_bound: T,
lower_value: T,
upper_value: T,
lower_derivative: T,
upper_derivative: T,
is_increasing: bool,
) -> Extrapolator<T> {
if is_increasing {
if lower_derivative > T::zero() && upper_derivative > T::zero() {
let rate = T::from(0.1).expect("Operation failed"); make_exponential_extrapolator(
lower_bound,
upper_bound,
lower_value,
upper_value,
lower_derivative,
upper_derivative,
rate,
T::zero(),
)
} else {
make_linear_extrapolator(
lower_bound,
upper_bound,
lower_value,
upper_value,
lower_derivative,
upper_derivative,
)
}
} else {
let rate = T::from(-0.1).expect("Operation failed"); make_exponential_extrapolator(
lower_bound,
upper_bound,
lower_value,
upper_value,
lower_derivative,
upper_derivative,
rate,
T::zero(),
)
}
}
pub fn make_high_confidence_extrapolator<T: Float + std::fmt::Display + Default + AddAssign>(
lower_bound: T,
upper_bound: T,
lower_value: T,
upper_value: T,
lower_derivative: T,
upper_derivative: T,
confidence_level: T,
) -> AdvancedExtrapolator<T> {
let base_extrapolator = make_linear_extrapolator(
lower_bound,
upper_bound,
lower_value,
upper_value,
lower_derivative,
upper_derivative,
);
make_confidence_extrapolator(base_extrapolator, confidence_level, 1000)
}