Skip to content

Commit

Permalink
REF: splines restructure
Browse files Browse the repository at this point in the history
  • Loading branch information
attack68 committed Sep 24, 2024
1 parent 7b4b0c4 commit 97cf3de
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 68 deletions.
91 changes: 41 additions & 50 deletions rust/curves/interpolation/intp_log_cubic.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use crate::curves::interpolation::utils::log_linear_interp;
use crate::curves::nodes::NodesTimestamp;
use crate::curves::CurveInterpolation;
use crate::dual::DualsOrF64;
use crate::dual::{Number, ADOrder, NumberPPSpline, set_order_clone, Dual, Dual2};
use crate::splines::{PPSplineF64, PPSplineDual, PPSplineDual2};
use bincode::{deserialize, serialize};
use chrono::NaiveDateTime;
use pyo3::prelude::*;
Expand All @@ -12,56 +13,48 @@ use std::cmp::PartialEq;

/// Define log-linear interpolation of nodes.
#[pyclass(module = "rateslib.rs")]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct LogCubicInterpolator<T: NumberMapping> {
spline: T
#[derive(Clone, PartialEq, Serialize, Deserialize)]
pub struct LogCubicInterpolator {
spline: NumberPPSpline
}

#[pymethods]
impl<T> LogCubicInterpolator
where T: PartialOrd + Signed + Clone + Sum + Zero,
for<'a> &'a T: Sub<&'a T, Output = T>,
for<'a> &'a f64: Mul<&'a T, Output = T>,
{
impl LogCubicInterpolator {
#[new]
pub fn new(t: Vec<f64>, c: Option<Vec<T>>) -> Self {
let spline: PPSpline<T> = PPSpline.new(3_usize, t, c);
LogCubicInterpolator {
spline
}
}

// Pickling
pub fn __setstate__(&mut self, state: Bound<'_, PyBytes>) -> PyResult<()> {
*self = deserialize(state.as_bytes()).unwrap();
Ok(())
}
pub fn __getstate__<'py>(&self, py: Python<'py>) -> PyResult<Bound<'py, PyBytes>> {
Ok(PyBytes::new_bound(py, &serialize(&self).unwrap()))
}
pub fn __getnewargs__<'py>(&self, py: Python<'py>) -> PyResult<(Vec<f64>, Option<Vec<T>>)> {
Ok((self.t.clone(), ))
}
}

impl CurveInterpolation for LogLinearInterpolator {
fn interpolated_value(&self, nodes: &NodesTimestamp, date: &NaiveDateTime) -> DualsOrF64 {
let x = date.and_utc().timestamp();
let index = self.node_index(nodes, x);

macro_rules! interp {
($Variant: ident, $indexmap: expr) => {{
let (x1, y1) = $indexmap.get_index(index).unwrap();
let (x2, y2) = $indexmap.get_index(index + 1_usize).unwrap();
DualsOrF64::$Variant(log_linear_interp(*x1 as f64, y1, *x2 as f64, y2, x as f64))
}};
}
match nodes {
NodesTimestamp::F64(m) => interp!(F64, m),
NodesTimestamp::Dual(m) => interp!(Dual, m),
NodesTimestamp::Dual2(m) => interp!(Dual2, m),
pub fn new(t: Vec<f64>, ad: ADOrder, c: Option<Vec<Number>>) -> Self {
match (c, ad) {
(Some(v), ADOrder::Zero) => {
let c_: Vec<f64> = v.iter().map(|x| set_order_clone(&x, ADOrder::Zero, vec![])).map(f64::from).collect();
let spline = NumberPPSpline::F64(PPSplineF64::new(3, t, Some(c_)));
LogCubicInterpolator {spline}
}
(Some(v), ADOrder::One) => {
let c_: Vec<Dual> = v.iter().map(|x| set_order_clone(&x, ADOrder::One, vec![])).map(Dual::from).collect();
let spline = NumberPPSpline::Dual(PPSplineDual::new(3, t, Some(c_)));
LogCubicInterpolator {spline}
}
(Some(v), ADOrder::Two) => {
let c_: Vec<Dual2> = v.iter().map(|x| set_order_clone(&x, ADOrder::Zero, vec![])).map(Dual2::from).collect();
let spline = NumberPPSpline::Dual2(PPSplineDual2::new(3, t, Some(c_)));
LogCubicInterpolator {spline}
}
(None, ADOrder::Zero) => {LogCubicInterpolator {spline: NumberPPSpline::F64(PPSplineF64::new(3, t, None))}},
(None, ADOrder::One) => {LogCubicInterpolator {spline: NumberPPSpline::Dual(PPSplineDual::new(3, t, None))}},
(None, ADOrder::Two) => {LogCubicInterpolator {spline: NumberPPSpline::Dual2(PPSplineDual2::new(3, t, None))}},
}
}
//
// // Pickling
// pub fn __setstate__(&mut self, state: Bound<'_, PyBytes>) -> PyResult<()> {
// *self = deserialize(state.as_bytes()).unwrap();
// Ok(())
// }
// pub fn __getstate__<'py>(&self, py: Python<'py>) -> PyResult<Bound<'py, PyBytes>> {
// Ok(PyBytes::new_bound(py, &serialize(&self).unwrap()))
// }
// pub fn __getnewargs__<'py>(&self, py: Python<'py>) -> PyResult<(Vec<f64>, Option<Vec<T>>)> {
// Ok((self.t.clone(), ))
// }
}

#[cfg(test)]
Expand All @@ -81,11 +74,9 @@ mod tests {
}

#[test]
fn test_log_linear() {
fn test_log_cubic() {
let nts = nodes_timestamp_fixture();
let ll = LogLinearInterpolator::new();
let result = ll.interpolated_value(&nts, &ndt(2000, 7, 1));
// expected = exp(0 + (182 / 366) * (ln(0.99) - ln(1.0)) = 0.995015
assert_eq!(result, DualsOrF64::F64(0.9950147597711371));
let t = vec![1.0,1.0,1.0,1.0, 2.0, 3.0,3.0,3.0,3.0];
let ll = LogCubicInterpolator::new(t, ADOrder::Zero, None);
}
}
1 change: 1 addition & 0 deletions rust/curves/interpolation/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ pub(crate) mod intp_flat_forward;
pub(crate) mod intp_linear;
pub(crate) mod intp_linear_zero_rate;
pub(crate) mod intp_log_linear;
pub(crate) mod intp_log_cubic;
pub(crate) mod intp_null;

pub(crate) mod utils;
58 changes: 41 additions & 17 deletions rust/splines/spline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -399,26 +399,50 @@ where
}
}

/// Definitive [f64] type variant of a [PPSpline].
#[pyclass(module = "rateslib.rs")]
#[derive(Clone, Deserialize, Serialize)]
pub struct PPSplineF64 {
pub(crate) inner: PPSpline<f64>,
}
// /// Definitive [f64] type variant of a [PPSpline].
// #[pyclass(module = "rateslib.rs")]
// #[derive(Clone, Deserialize, Serialize)]
// pub struct PPSplineF64 {
// pub(crate) inner: PPSpline<f64>,
// }
//
// /// Definitive [Dual] type variant of a [PPSpline].
// #[pyclass(module = "rateslib.rs")]
// #[derive(Clone, Deserialize, Serialize)]
// pub struct PPSplineDual {
// pub(crate) inner: PPSpline<Dual>,
// }
//
// /// Definitive [Dual2] type variant of a [PPSpline].
// #[pyclass(module = "rateslib.rs")]
// #[derive(Clone, Deserialize, Serialize)]
// pub struct PPSplineDual2 {
// pub(crate) inner: PPSpline<Dual2>,
// }

macro_rules! define_specific_type_splines {
($name: ident, $type: ident) => {

#[doc = concat!("Definitive [", stringify!($type), "] type variant of a [PPSpline]")]
#[pyclass(module = "rateslib.rs")]
#[derive(Clone, Deserialize, Serialize)]
pub struct $name {
pub(crate) inner: PPSpline<$type>,
}

/// Definitive [Dual] type variant of a [PPSpline].
#[pyclass(module = "rateslib.rs")]
#[derive(Clone, Deserialize, Serialize)]
pub struct PPSplineDual {
pub(crate) inner: PPSpline<Dual>,
impl $name {
pub fn new(k: usize, t: Vec<f64>, c: Option<Vec<$type>>) -> Self {
Self {
inner: PPSpline::new(k, t, c),
}
}
}
}
}
define_specific_type_splines!(PPSplineF64, f64);
define_specific_type_splines!(PPSplineDual, Dual);
define_specific_type_splines!(PPSplineDual2, Dual2);

/// Definitive [Dual2] type variant of a [PPSpline].
#[pyclass(module = "rateslib.rs")]
#[derive(Clone, Deserialize, Serialize)]
pub struct PPSplineDual2 {
pub(crate) inner: PPSpline<Dual2>,
}

impl PartialEq for PPSplineF64 {
/// Equality of `PPSplineF64` if
Expand Down
2 changes: 1 addition & 1 deletion rust/splines/spline_py.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ macro_rules! create_interface {
#[pymethods]
impl $name {
#[new]
fn new(k: usize, t: Vec<f64>, c: Option<Vec<$type>>) -> Self {
fn new_py(k: usize, t: Vec<f64>, c: Option<Vec<$type>>) -> Self {
Self {
inner: PPSpline::new(k, t, c),
}
Expand Down

0 comments on commit 97cf3de

Please sign in to comment.