use crate::core::{
check_eq_len, rolling_extreme_index, rolling_max, rolling_min, rolling_minmax, rolling_sum,
};
use crate::error::{check_period, TaError};
use crate::indicator::indicator;
indicator! {
fn add(real0: &[f64], real1: &[f64]) -> Vec<f64> with add_with_output;
}
pub fn add_with_output(real0: &[f64], real1: &[f64], out: &mut [f64]) -> Result<(), TaError> {
check_eq_len(&[real0, real1], "add")?;
if out.len() != real0.len() {
return Err(TaError::BadParam(
"add_with_output: out length must equal real0 length".into(),
));
}
for ((o, &a), &b) in out.iter_mut().zip(real0.iter()).zip(real1.iter()) {
*o = a + b;
}
Ok(())
}
indicator! {
fn sub(real0: &[f64], real1: &[f64]) -> Vec<f64> with sub_with_output;
}
pub fn sub_with_output(real0: &[f64], real1: &[f64], out: &mut [f64]) -> Result<(), TaError> {
check_eq_len(&[real0, real1], "sub")?;
if out.len() != real0.len() {
return Err(TaError::BadParam(
"sub_with_output: out length must equal real0 length".into(),
));
}
for ((o, &a), &b) in out.iter_mut().zip(real0.iter()).zip(real1.iter()) {
*o = a - b;
}
Ok(())
}
indicator! {
fn mult(real0: &[f64], real1: &[f64]) -> Vec<f64> with mult_with_output;
}
pub fn mult_with_output(real0: &[f64], real1: &[f64], out: &mut [f64]) -> Result<(), TaError> {
check_eq_len(&[real0, real1], "mult")?;
if out.len() != real0.len() {
return Err(TaError::BadParam(
"mult_with_output: out length must equal real0 length".into(),
));
}
for ((o, &a), &b) in out.iter_mut().zip(real0.iter()).zip(real1.iter()) {
*o = a * b;
}
Ok(())
}
indicator! {
fn div(real0: &[f64], real1: &[f64]) -> Vec<f64> with div_with_output;
}
pub fn div_with_output(real0: &[f64], real1: &[f64], out: &mut [f64]) -> Result<(), TaError> {
check_eq_len(&[real0, real1], "div")?;
if out.len() != real0.len() {
return Err(TaError::BadParam(
"div_with_output: out length must equal real0 length".into(),
));
}
for ((o, &a), &b) in out.iter_mut().zip(real0.iter()).zip(real1.iter()) {
*o = a / b;
}
Ok(())
}
indicator! {
fn max(values: &[f64], time_period: usize) -> Vec<f64> with max_with_output;
}
pub fn max_with_output(values: &[f64], time_period: usize, out: &mut [f64]) -> Result<(), TaError> {
check_period(time_period)?;
if out.len() != values.len() {
return Err(TaError::BadParam(
"max_with_output: out length must equal values length".into(),
));
}
let r = rolling_max(values, time_period);
out.copy_from_slice(&r);
Ok(())
}
indicator! {
fn min(values: &[f64], time_period: usize) -> Vec<f64> with min_with_output;
}
pub fn min_with_output(values: &[f64], time_period: usize, out: &mut [f64]) -> Result<(), TaError> {
check_period(time_period)?;
if out.len() != values.len() {
return Err(TaError::BadParam(
"min_with_output: out length must equal values length".into(),
));
}
let r = rolling_min(values, time_period);
out.copy_from_slice(&r);
Ok(())
}
indicator! {
fn sum(values: &[f64], time_period: usize) -> Vec<f64> with sum_with_output;
}
pub fn sum_with_output(values: &[f64], time_period: usize, out: &mut [f64]) -> Result<(), TaError> {
check_period(time_period)?;
if out.len() != values.len() {
return Err(TaError::BadParam(
"sum_with_output: out length must equal values length".into(),
));
}
let r = rolling_sum(values, time_period);
out.copy_from_slice(&r);
Ok(())
}
indicator! {
fn max_index(values: &[f64], time_period: usize) -> Vec<f64> with max_index_with_output;
}
pub fn max_index_with_output(
values: &[f64],
time_period: usize,
out: &mut [f64],
) -> Result<(), TaError> {
check_period(time_period)?;
if out.len() != values.len() {
return Err(TaError::BadParam(
"max_index_with_output: out length must equal values length".into(),
));
}
let r = rolling_extreme_index(values, time_period, true);
out.copy_from_slice(&r);
Ok(())
}
indicator! {
fn min_index(values: &[f64], time_period: usize) -> Vec<f64> with min_index_with_output;
}
pub fn min_index_with_output(
values: &[f64],
time_period: usize,
out: &mut [f64],
) -> Result<(), TaError> {
check_period(time_period)?;
if out.len() != values.len() {
return Err(TaError::BadParam(
"min_index_with_output: out length must equal values length".into(),
));
}
let r = rolling_extreme_index(values, time_period, false);
out.copy_from_slice(&r);
Ok(())
}
pub struct MinMax {
pub min: Vec<f64>,
pub max: Vec<f64>,
}
pub fn minmax(values: &[f64], time_period: usize) -> Result<MinMax, TaError> {
check_period(time_period)?;
let n = values.len();
let mut out = MinMax {
min: vec![f64::NAN; n],
max: vec![f64::NAN; n],
};
minmax_with_output(values, time_period, &mut out)?;
Ok(out)
}
pub fn minmax_with_output(
values: &[f64],
time_period: usize,
out: &mut MinMax,
) -> Result<(), TaError> {
check_period(time_period)?;
let n = values.len();
if out.min.len() != n || out.max.len() != n {
return Err(TaError::BadParam(
"minmax_with_output: out vectors must have length == values length".into(),
));
}
#[cfg(feature = "parallel")]
{
if n >= 8192 {
return minmax_parallel_with_output(values, time_period, out);
}
}
minmax_serial_with_output(values, time_period, out)
}
fn minmax_serial_with_output(
values: &[f64],
time_period: usize,
out: &mut MinMax,
) -> Result<(), TaError> {
let (mx, mn) = rolling_minmax(values, time_period);
out.max.copy_from_slice(&mx);
out.min.copy_from_slice(&mn);
Ok(())
}
pub fn minmax_serial(values: &[f64], time_period: usize) -> Result<MinMax, TaError> {
check_period(time_period)?;
let n = values.len();
let mut out = MinMax {
min: vec![f64::NAN; n],
max: vec![f64::NAN; n],
};
minmax_serial_with_output(values, time_period, &mut out)?;
Ok(out)
}
#[cfg(feature = "parallel")]
pub fn minmax_parallel(values: &[f64], time_period: usize) -> Result<MinMax, TaError> {
check_period(time_period)?;
let n = values.len();
let mut out = MinMax {
min: vec![f64::NAN; n],
max: vec![f64::NAN; n],
};
minmax_parallel_with_output(values, time_period, &mut out)?;
Ok(out)
}
#[cfg(feature = "parallel")]
fn minmax_parallel_with_output(
values: &[f64],
time_period: usize,
out: &mut MinMax,
) -> Result<(), TaError> {
check_period(time_period)?;
let n = values.len();
if out.min.len() != n || out.max.len() != n {
return Err(TaError::BadParam(
"minmax_parallel_with_output: out vectors must have length == values length".into(),
));
}
let p = time_period;
crate::parallel::parallel_index_map_2(
n,
p - 1,
&mut out.min,
&mut out.max,
|start, end| {
let (mx, mn) = rolling_minmax(&values[start..end], p);
(mn, mx)
},
);
Ok(())
}
pub struct MinMaxIndex {
pub min_idx: Vec<f64>,
pub max_idx: Vec<f64>,
}
pub fn minmax_index(values: &[f64], time_period: usize) -> Result<MinMaxIndex, TaError> {
check_period(time_period)?;
let n = values.len();
let mut out = MinMaxIndex {
min_idx: vec![f64::NAN; n],
max_idx: vec![f64::NAN; n],
};
minmax_index_with_output(values, time_period, &mut out)?;
Ok(out)
}
pub fn minmax_index_with_output(
values: &[f64],
time_period: usize,
out: &mut MinMaxIndex,
) -> Result<(), TaError> {
check_period(time_period)?;
let n = values.len();
if out.min_idx.len() != n || out.max_idx.len() != n {
return Err(TaError::BadParam(
"minmax_index_with_output: out vectors must have length == values length".into(),
));
}
#[cfg(feature = "parallel")]
{
if n >= 8192 {
return minmax_index_parallel_with_output(values, time_period, out);
}
}
minmax_index_serial_with_output(values, time_period, out)
}
fn minmax_index_serial_with_output(
values: &[f64],
time_period: usize,
out: &mut MinMaxIndex,
) -> Result<(), TaError> {
let min_idx = rolling_extreme_index(values, time_period, false);
let max_idx = rolling_extreme_index(values, time_period, true);
out.min_idx.copy_from_slice(&min_idx);
out.max_idx.copy_from_slice(&max_idx);
Ok(())
}
pub fn minmax_index_serial(values: &[f64], time_period: usize) -> Result<MinMaxIndex, TaError> {
check_period(time_period)?;
let n = values.len();
let mut out = MinMaxIndex {
min_idx: vec![f64::NAN; n],
max_idx: vec![f64::NAN; n],
};
minmax_index_serial_with_output(values, time_period, &mut out)?;
Ok(out)
}
#[cfg(feature = "parallel")]
pub fn minmax_index_parallel(values: &[f64], time_period: usize) -> Result<MinMaxIndex, TaError> {
check_period(time_period)?;
let n = values.len();
let mut out = MinMaxIndex {
min_idx: vec![f64::NAN; n],
max_idx: vec![f64::NAN; n],
};
minmax_index_parallel_with_output(values, time_period, &mut out)?;
Ok(out)
}
#[cfg(feature = "parallel")]
fn minmax_index_parallel_with_output(
values: &[f64],
time_period: usize,
out: &mut MinMaxIndex,
) -> Result<(), TaError> {
check_period(time_period)?;
let n = values.len();
if out.min_idx.len() != n || out.max_idx.len() != n {
return Err(TaError::BadParam(
"minmax_index_parallel_with_output: out vectors must have length == values length".into(),
));
}
let p = time_period;
crate::parallel::parallel_index_map_2(
n,
p - 1,
&mut out.min_idx,
&mut out.max_idx,
|start, end| {
let off = start as f64;
let mut min_idx = rolling_extreme_index(&values[start..end], p, false);
let mut max_idx = rolling_extreme_index(&values[start..end], p, true);
for (i, v) in min_idx.iter_mut().enumerate() {
if i >= p - 1 {
*v += off;
}
}
for (i, v) in max_idx.iter_mut().enumerate() {
if i >= p - 1 {
*v += off;
}
}
(min_idx, max_idx)
},
);
Ok(())
}