use crate::math::array::Array;
use crate::methods::finitedifferences::StepCondition;
use crate::methods::finitedifferences::meshers::FdmMesher;
use crate::methods::finitedifferences::utilities::FdmInnerValueCalculator;
use crate::shared::Shared;
use crate::types::Time;
pub struct FdmAmericanStepCondition {
mesher: Shared<dyn FdmMesher>,
calculator: Shared<dyn FdmInnerValueCalculator>,
exercise_start: Time,
}
impl FdmAmericanStepCondition {
pub fn new(
mesher: Shared<dyn FdmMesher>,
calculator: Shared<dyn FdmInnerValueCalculator>,
exercise_start: Time,
) -> FdmAmericanStepCondition {
FdmAmericanStepCondition {
mesher,
calculator,
exercise_start,
}
}
}
impl StepCondition for FdmAmericanStepCondition {
fn apply_to(&self, a: &mut Array, t: Time) {
if t < self.exercise_start {
return;
}
let layout = self.mesher.layout();
assert_eq!(layout.size(), a.size(), "inconsistent array dimensions");
for iter in layout.iter() {
let inner_value = self.calculator.inner_value(&iter, t);
if inner_value > a[iter.index()] {
a[iter.index()] = inner_value;
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::methods::finitedifferences::meshers::UniformGridMesher;
use crate::methods::finitedifferences::operators::{FdmLinearOpIterator, FdmLinearOpLayout};
use crate::shared::shared;
use crate::types::Real;
struct TabulatedInnerValue {
values: Vec<Real>,
}
impl FdmInnerValueCalculator for TabulatedInnerValue {
fn inner_value(&self, iter: &FdmLinearOpIterator, _t: Time) -> Real {
self.values[iter.index()]
}
fn avg_inner_value(&self, iter: &FdmLinearOpIterator, t: Time) -> Real {
self.inner_value(iter, t)
}
}
fn condition(values: Vec<Real>, exercise_start: Time) -> FdmAmericanStepCondition {
let layout = shared(FdmLinearOpLayout::new(vec![values.len()]));
let mesher = shared(UniformGridMesher::new(layout, &[(0.0, 1.0)]).unwrap());
FdmAmericanStepCondition::new(
mesher as Shared<dyn FdmMesher>,
shared(TabulatedInnerValue { values }) as Shared<dyn FdmInnerValueCalculator>,
exercise_start,
)
}
#[test]
fn values_below_the_intrinsic_value_are_lifted_and_the_rest_are_left_alone() {
let condition = condition(vec![3.0, 1.0, 0.0], 0.0);
let mut values = Array::from([2.0, 1.5, 0.0]);
condition.apply_to(&mut values, 0.5);
assert_eq!(values, Array::from([3.0, 1.5, 0.0]));
}
#[test]
fn nothing_is_lifted_before_the_exercise_window_opens() {
let condition = condition(vec![3.0, 1.0, 0.0], 0.25);
let mut values = Array::from([2.0, 1.5, 0.0]);
let before = values.clone();
condition.apply_to(&mut values, 0.2);
assert_eq!(values, before);
}
#[test]
fn the_window_is_open_at_its_own_start() {
let condition = condition(vec![3.0, 1.0, 0.0], 0.25);
let mut values = Array::from([2.0, 1.5, 0.0]);
condition.apply_to(&mut values, 0.25);
assert_eq!(values, Array::from([3.0, 1.5, 0.0]));
}
}