Skip to content

Commit fd80cee

Browse files
committed
eval_no_ts_check initial implementation
1 parent 40ab4f7 commit fd80cee

40 files changed

+191
-127
lines changed

src/evaluator.rs

Lines changed: 27 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ pub struct EvaluatorInfo {
2020
pub m_required: bool,
2121
pub w_required: bool,
2222
pub sorting_required: bool,
23+
pub variability_required: bool,
2324
}
2425

2526
#[derive(Clone, Debug)]
@@ -69,6 +70,11 @@ pub trait EvaluatorInfoTrait {
6970
fn is_sorting_required(&self) -> bool {
7071
self.get_info().sorting_required
7172
}
73+
74+
/// If feature requires magnitude array elements to be different
75+
fn is_variability_required(&self) -> bool {
76+
self.get_info().variability_required
77+
}
7278
}
7379

7480
// impl<P> EvaluatorInfoTrait for P
@@ -124,8 +130,14 @@ pub trait FeatureEvaluator<T: Float>:
124130
+ DeserializeOwned
125131
+ JsonSchema
126132
{
133+
/// Version of [FeatureEvaluator::eval] which can panic for incorrect input
134+
fn eval_no_ts_check(&self, ts: &mut TimeSeries<T>) -> Result<Vec<T>, EvaluatorError>;
135+
127136
/// Vector of feature values or `EvaluatorError`
128-
fn eval(&self, ts: &mut TimeSeries<T>) -> Result<Vec<T>, EvaluatorError>;
137+
fn eval(&self, ts: &mut TimeSeries<T>) -> Result<Vec<T>, EvaluatorError> {
138+
self.check_ts(ts)?;
139+
self.eval_no_ts_check(ts)
140+
}
129141

130142
/// Returns vector of feature values and fill invalid components with given value
131143
fn eval_or_fill(&self, ts: &mut TimeSeries<T>, fill_value: T) -> Vec<T> {
@@ -135,44 +147,31 @@ pub trait FeatureEvaluator<T: Float>:
135147
}
136148
}
137149

150+
fn check_ts(&self, ts: &mut TimeSeries<T>) -> Result<(), EvaluatorError> {
151+
self.check_ts_length(ts)?;
152+
self.check_ts_variability(ts)
153+
}
154+
138155
/// Checks if [TimeSeries] has enough points to evaluate the feature
139-
fn check_ts_length(&self, ts: &TimeSeries<T>) -> Result<usize, EvaluatorError> {
156+
fn check_ts_length(&self, ts: &TimeSeries<T>) -> Result<(), EvaluatorError> {
140157
let length = ts.lenu();
141158
if length < self.min_ts_length() {
142159
Err(EvaluatorError::ShortTimeSeries {
143160
actual: length,
144161
minimum: self.min_ts_length(),
145162
})
146163
} else {
147-
Ok(length)
164+
Ok(())
148165
}
149166
}
150-
}
151167

152-
pub fn get_nonzero_m_std<T: Float>(ts: &mut TimeSeries<T>) -> Result<T, EvaluatorError> {
153-
let std = ts.m.get_std();
154-
if std.is_zero() || ts.is_plateau() {
155-
Err(EvaluatorError::FlatTimeSeries)
156-
} else {
157-
Ok(std)
158-
}
159-
}
160-
161-
pub fn get_nonzero_m_std2<T: Float>(ts: &mut TimeSeries<T>) -> Result<T, EvaluatorError> {
162-
let std2 = ts.m.get_std2();
163-
if std2.is_zero() || ts.is_plateau() {
164-
Err(EvaluatorError::FlatTimeSeries)
165-
} else {
166-
Ok(std2)
167-
}
168-
}
169-
170-
pub fn get_nonzero_reduced_chi2<T: Float>(ts: &mut TimeSeries<T>) -> Result<T, EvaluatorError> {
171-
let reduced_chi2 = ts.get_m_reduced_chi2();
172-
if reduced_chi2.is_zero() || ts.is_plateau() {
173-
Err(EvaluatorError::FlatTimeSeries)
174-
} else {
175-
Ok(reduced_chi2)
168+
/// Checks if [TimeSeries] meets variability requirement
169+
fn check_ts_variability(&self, ts: &mut TimeSeries<T>) -> Result<(), EvaluatorError> {
170+
if self.is_variability_required() && ts.is_plateau() {
171+
Err(EvaluatorError::FlatTimeSeries)
172+
} else {
173+
Ok(())
174+
}
176175
}
177176
}
178177

src/extractor.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ where
4646
m_required: features.iter().any(|x| x.is_m_required()),
4747
w_required: features.iter().any(|x| x.is_w_required()),
4848
sorting_required: features.iter().any(|x| x.is_sorting_required()),
49+
variability_required: features.iter().any(|x| x.is_variability_required()),
4950
}
5051
.into();
5152
Self {
@@ -118,10 +119,10 @@ where
118119
T: Float,
119120
F: FeatureEvaluator<T>,
120121
{
121-
fn eval(&self, ts: &mut TimeSeries<T>) -> Result<Vec<T>, EvaluatorError> {
122+
fn eval_no_ts_check(&self, ts: &mut TimeSeries<T>) -> Result<Vec<T>, EvaluatorError> {
122123
let mut vec = Vec::with_capacity(self.size_hint());
123124
for x in &self.features {
124-
vec.extend(x.eval(ts)?);
125+
vec.extend(x.eval_no_ts_check(ts)?);
125126
}
126127
Ok(vec)
127128
}

src/features/amplitude.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ lazy_info!(
4747
m_required: true,
4848
w_required: false,
4949
sorting_required: false,
50+
variability_required: false,
5051
);
5152

5253
impl FeatureNamesDescriptionsTrait for Amplitude {
@@ -63,8 +64,7 @@ impl<T> FeatureEvaluator<T> for Amplitude
6364
where
6465
T: Float,
6566
{
66-
fn eval(&self, ts: &mut TimeSeries<T>) -> Result<Vec<T>, EvaluatorError> {
67-
self.check_ts_length(ts)?;
67+
fn eval_no_ts_check(&self, ts: &mut TimeSeries<T>) -> Result<Vec<T>, EvaluatorError> {
6868
Ok(vec![T::half() * (ts.m.get_max() - ts.m.get_min())])
6969
}
7070
}

src/features/anderson_darling_normal.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ lazy_info!(
4646
m_required: true,
4747
w_required: false,
4848
sorting_required: false,
49+
variability_required: true,
4950
);
5051

5152
impl FeatureNamesDescriptionsTrait for AndersonDarlingNormal {
@@ -62,10 +63,10 @@ impl<T> FeatureEvaluator<T> for AndersonDarlingNormal
6263
where
6364
T: Float,
6465
{
65-
fn eval(&self, ts: &mut TimeSeries<T>) -> Result<Vec<T>, EvaluatorError> {
66-
let size = self.check_ts_length(ts)?;
67-
let m_std = get_nonzero_m_std(ts)?;
66+
fn eval_no_ts_check(&self, ts: &mut TimeSeries<T>) -> Result<Vec<T>, EvaluatorError> {
67+
let size = ts.lenu();
6868
let m_mean = ts.m.get_mean();
69+
let m_std = ts.m.get_std();
6970
let sum: f64 =
7071
ts.m.get_sorted()
7172
.as_ref()

src/features/bazin_fit.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ lazy_info!(
108108
m_required: true,
109109
w_required: true,
110110
sorting_required: true, // improve reproducibility
111+
variability_required: false,
111112
);
112113

113114
struct Params<'a, T> {

src/features/beyond_n_std.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ lazy_info!(
9494
m_required: true,
9595
w_required: false,
9696
sorting_required: false,
97+
variability_required: false,
9798
);
9899

99100
impl<T> Default for BeyondNStd<T>
@@ -122,8 +123,7 @@ impl<T> FeatureEvaluator<T> for BeyondNStd<T>
122123
where
123124
T: Float,
124125
{
125-
fn eval(&self, ts: &mut TimeSeries<T>) -> Result<Vec<T>, EvaluatorError> {
126-
self.check_ts_length(ts)?;
126+
fn eval_no_ts_check(&self, ts: &mut TimeSeries<T>) -> Result<Vec<T>, EvaluatorError> {
127127
let m_mean = ts.m.get_mean();
128128
let threshold = ts.m.get_std() * self.nstd;
129129
let count_beyond = ts.m.sample.fold(0, |count, &m| {

src/features/bins.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ where
6262
m_required: true,
6363
w_required: true,
6464
sorting_required: true,
65+
variability_required: false,
6566
};
6667
Self {
6768
properties: EvaluatorProperties {
@@ -92,6 +93,9 @@ where
9293
let window = self.window;
9394
let offset = self.offset;
9495
self.properties.info.size += feature.size_hint();
96+
self.properties.info.min_ts_length =
97+
usize::max(self.properties.info.min_ts_length, feature.min_ts_length());
98+
self.properties.info.variability_required |= feature.is_variability_required();
9599
self.properties.names.extend(
96100
feature
97101
.get_names()
@@ -133,7 +137,12 @@ where
133137
}
134138

135139
fn transform_ts(&self, ts: &mut TimeSeries<T>) -> Result<TmwArrays<T>, EvaluatorError> {
136-
self.check_ts_length(ts)?;
140+
if ts.lenu() == 0 {
141+
return Err(EvaluatorError::ShortTimeSeries {
142+
actual: ts.lenu(),
143+
minimum: 1,
144+
});
145+
}
137146
let (t, m, w): (Vec<_>, Vec<_>, Vec<_>) =
138147
ts.t.as_slice()
139148
.iter()

src/features/cusum.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ lazy_info!(
4646
m_required: true,
4747
w_required: false,
4848
sorting_required: true,
49+
variability_required: true,
4950
);
5051

5152
impl FeatureNamesDescriptionsTrait for Cusum {
@@ -62,10 +63,9 @@ impl<T> FeatureEvaluator<T> for Cusum
6263
where
6364
T: Float,
6465
{
65-
fn eval(&self, ts: &mut TimeSeries<T>) -> Result<Vec<T>, EvaluatorError> {
66-
self.check_ts_length(ts)?;
67-
let m_std = get_nonzero_m_std(ts)?;
66+
fn eval_no_ts_check(&self, ts: &mut TimeSeries<T>) -> Result<Vec<T>, EvaluatorError> {
6867
let m_mean = ts.m.get_mean();
68+
let m_std = ts.m.get_std();
6969
let (_last_cusum, min_cusum, max_cusum) = ts.m.as_slice().iter().fold(
7070
(T::zero(), T::infinity(), -T::infinity()),
7171
|(mut cusum, min_cusum, max_cusum), &m| {

src/features/duration.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ lazy_info!(
3939
m_required: false,
4040
w_required: false,
4141
sorting_required: true,
42+
variability_required: false,
4243
);
4344

4445
impl FeatureNamesDescriptionsTrait for Duration {
@@ -55,8 +56,7 @@ impl<T> FeatureEvaluator<T> for Duration
5556
where
5657
T: Float,
5758
{
58-
fn eval(&self, ts: &mut TimeSeries<T>) -> Result<Vec<T>, EvaluatorError> {
59-
self.check_ts_length(ts)?;
59+
fn eval_no_ts_check(&self, ts: &mut TimeSeries<T>) -> Result<Vec<T>, EvaluatorError> {
6060
Ok(vec![ts.t.sample[ts.lenu() - 1] - ts.t.sample[0]])
6161
}
6262
}

src/features/eta.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ lazy_info!(
4242
m_required: true,
4343
w_required: false,
4444
sorting_required: true,
45+
variability_required: true,
4546
);
4647

4748
impl FeatureNamesDescriptionsTrait for Eta {
@@ -58,9 +59,8 @@ impl<T> FeatureEvaluator<T> for Eta
5859
where
5960
T: Float,
6061
{
61-
fn eval(&self, ts: &mut TimeSeries<T>) -> Result<Vec<T>, EvaluatorError> {
62-
self.check_ts_length(ts)?;
63-
let m_std2 = get_nonzero_m_std2(ts)?;
62+
fn eval_no_ts_check(&self, ts: &mut TimeSeries<T>) -> Result<Vec<T>, EvaluatorError> {
63+
let m_std2 = ts.m.get_std2();
6464
let value =
6565
ts.m.as_slice()
6666
.iter()

0 commit comments

Comments
 (0)