Skip to content

Commit e854863

Browse files
committed
Color features
1 parent 50027d2 commit e854863

File tree

6 files changed

+259
-24
lines changed

6 files changed

+259
-24
lines changed

src/data/multi_color_time_series.rs

Lines changed: 29 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@ use std::ops::{Deref, DerefMut};
1111

1212
pub struct MultiColorTimeSeries<'a, P: PassbandTrait, T: Float>(BTreeMap<P, TimeSeries<'a, T>>);
1313

14-
impl<'a, P, T> MultiColorTimeSeries<'a, P, T>
14+
impl<'a, 'p, P, T> MultiColorTimeSeries<'a, P, T>
1515
where
16-
P: PassbandTrait,
16+
P: PassbandTrait + 'p,
1717
T: Float,
1818
{
1919
pub fn new(map: impl Into<BTreeMap<P, TimeSeries<'a, T>>>) -> Self {
@@ -31,7 +31,7 @@ where
3131
{
3232
match passband_set {
3333
PassbandSet::AllAvailable => Either::Left(self.0.iter().map(|(p, ts)| (p, Some(ts)))),
34-
PassbandSet::FixedSet(set) => Either::Right(set.iter().map(|p| (p, self.0.get(p)))),
34+
PassbandSet::FixedSet(set) => Either::Right(self.iter_matched_passbands(set.iter())),
3535
}
3636
}
3737

@@ -48,20 +48,34 @@ where
4848
PassbandSet::AllAvailable => {
4949
Either::Left(self.0.iter_mut().map(|(p, ts)| (p, Some(ts))))
5050
}
51-
PassbandSet::FixedSet(set) => Either::Right(
52-
set.iter()
53-
.merge_join_by(self.0.iter_mut(), |p1, (p2, _ts)| p1.cmp(p2))
54-
.filter_map(|either_or_both| match either_or_both {
55-
// mcts misses required passband
56-
EitherOrBoth::Left(p) => Some((p, None)),
57-
// mcts has some passban passband_set doesn't require
58-
EitherOrBoth::Right(_) => None,
59-
// passbands match
60-
EitherOrBoth::Both(p, (_, ts)) => Some((p, Some(ts))),
61-
}),
62-
),
51+
PassbandSet::FixedSet(set) => {
52+
Either::Right(self.iter_matched_passbands_mut(set.iter()))
53+
}
6354
}
6455
}
56+
57+
pub fn iter_matched_passbands(
58+
&self,
59+
passband_it: impl Iterator<Item = &'p P>,
60+
) -> impl Iterator<Item = (&'p P, Option<&TimeSeries<'a, T>>)> {
61+
passband_it.map(|p| (p, self.0.get(p)))
62+
}
63+
64+
pub fn iter_matched_passbands_mut(
65+
&mut self,
66+
passband_it: impl Iterator<Item = &'p P>,
67+
) -> impl Iterator<Item = (&'p P, Option<&mut TimeSeries<'a, T>>)> {
68+
passband_it
69+
.merge_join_by(self.0.iter_mut(), |p1, (p2, _ts)| p1.cmp(p2))
70+
.filter_map(|either_or_both| match either_or_both {
71+
// mcts misses required passband
72+
EitherOrBoth::Left(p) => Some((p, None)),
73+
// mcts has some passban passband_set doesn't require
74+
EitherOrBoth::Right(_) => None,
75+
// passbands match
76+
EitherOrBoth::Both(p, (_, ts)) => Some((p, Some(ts))),
77+
})
78+
}
6579
}
6680

6781
impl<'a, P: PassbandTrait, T: Float> Deref for MultiColorTimeSeries<'a, P, T> {
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
use crate::data::MultiColorTimeSeries;
2+
use crate::error::MultiColorEvaluatorError;
3+
use crate::evaluator::{EvaluatorInfo, EvaluatorInfoTrait, FeatureNamesDescriptionsTrait};
4+
use crate::float_trait::Float;
5+
use crate::multicolor::multicolor_evaluator::*;
6+
use crate::multicolor::{PassbandSet, PassbandTrait};
7+
8+
pub use lazy_static::lazy_static;
9+
pub use schemars::JsonSchema;
10+
pub use serde::{Deserialize, Serialize};
11+
use std::collections::BTreeSet;
12+
use std::fmt::Debug;
13+
14+
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
15+
#[serde(bound(deserialize = "P: PassbandTrait + Deserialize<'de>"))]
16+
pub struct ColorOfMaximum<P>
17+
where
18+
P: Ord,
19+
{
20+
passband_set: PassbandSet<P>,
21+
passbands: [P; 2],
22+
name: String,
23+
description: String,
24+
}
25+
26+
impl<P> ColorOfMaximum<P>
27+
where
28+
P: PassbandTrait,
29+
{
30+
pub fn new(passbands: [P; 2]) -> Self {
31+
let set: BTreeSet<_> = passbands.clone().into();
32+
Self {
33+
passband_set: set.into(),
34+
name: format!("color_max_{}_{}", passbands[0].name(), passbands[1].name()),
35+
description: format!(
36+
"difference of maximum value magnitudes {}-{}",
37+
passbands[0].name(),
38+
passbands[1].name()
39+
),
40+
passbands,
41+
}
42+
}
43+
}
44+
45+
lazy_info!(
46+
COLOR_OF_MAXIMUM_INFO,
47+
size: 1,
48+
min_ts_length: 1,
49+
t_required: false,
50+
m_required: true,
51+
w_required: false,
52+
sorting_required: false,
53+
variability_required: false,
54+
);
55+
56+
impl<P> EvaluatorInfoTrait for ColorOfMaximum<P>
57+
where
58+
P: Ord,
59+
{
60+
fn get_info(&self) -> &EvaluatorInfo {
61+
&COLOR_OF_MAXIMUM_INFO
62+
}
63+
}
64+
65+
impl<P> FeatureNamesDescriptionsTrait for ColorOfMaximum<P>
66+
where
67+
P: Ord,
68+
{
69+
fn get_names(&self) -> Vec<&str> {
70+
vec![self.name.as_str()]
71+
}
72+
73+
fn get_descriptions(&self) -> Vec<&str> {
74+
vec![self.description.as_str()]
75+
}
76+
}
77+
78+
impl<P> MultiColorPassbandSetTrait<P> for ColorOfMaximum<P>
79+
where
80+
P: PassbandTrait,
81+
{
82+
fn get_passband_set(&self) -> &PassbandSet<P> {
83+
&self.passband_set
84+
}
85+
}
86+
87+
impl<P, T> MultiColorEvaluator<P, T> for ColorOfMaximum<P>
88+
where
89+
P: PassbandTrait,
90+
T: Float,
91+
{
92+
fn eval_multicolor_no_mcts_check(
93+
&self,
94+
mcts: &mut MultiColorTimeSeries<P, T>,
95+
) -> Result<Vec<T>, MultiColorEvaluatorError> {
96+
let mut maxima = [T::zero(); 2];
97+
for ((_passband, mcts), maximum) in mcts
98+
.iter_matched_passbands_mut(self.passbands.iter())
99+
.zip(maxima.iter_mut())
100+
{
101+
let mcts = mcts.expect("MultiColorTimeSeries must have all required passbands");
102+
*maximum = mcts.m.get_max()
103+
}
104+
Ok(vec![maxima[0] - maxima[1]])
105+
}
106+
}

src/multicolor/features/color_of_median.rs

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -103,16 +103,17 @@ where
103103
mcts: &mut MultiColorTimeSeries<P, T>,
104104
) -> Result<Vec<T>, MultiColorEvaluatorError> {
105105
let mut medians = [T::zero(); 2];
106-
for (median, passband) in medians.iter_mut().zip(self.passbands.iter()) {
107-
*median = self
108-
.median
109-
.eval(mcts.get_mut(passband).expect(
110-
"we checked all needed passbands are in mcts, but we still cannot find one",
111-
))
112-
.map_err(|error| MultiColorEvaluatorError::MonochromeEvaluatorError {
106+
for ((passband, mcts), median) in mcts
107+
.iter_matched_passbands_mut(self.passbands.iter())
108+
.zip(medians.iter_mut())
109+
{
110+
let mcts = mcts.expect("MultiColorTimeSeries must have all required passbands");
111+
*median = self.median.eval(mcts).map_err(|error| {
112+
MultiColorEvaluatorError::MonochromeEvaluatorError {
113113
passband: passband.name().into(),
114114
error,
115-
})?[0]
115+
}
116+
})?[0]
116117
}
117118
Ok(vec![medians[0] - medians[1]])
118119
}
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
use crate::data::MultiColorTimeSeries;
2+
use crate::error::MultiColorEvaluatorError;
3+
use crate::evaluator::{EvaluatorInfo, EvaluatorInfoTrait, FeatureNamesDescriptionsTrait};
4+
use crate::float_trait::Float;
5+
use crate::multicolor::multicolor_evaluator::*;
6+
use crate::multicolor::{PassbandSet, PassbandTrait};
7+
8+
pub use lazy_static::lazy_static;
9+
pub use schemars::JsonSchema;
10+
pub use serde::{Deserialize, Serialize};
11+
use std::collections::BTreeSet;
12+
use std::fmt::Debug;
13+
14+
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
15+
#[serde(bound(deserialize = "P: PassbandTrait + Deserialize<'de>"))]
16+
pub struct ColorOfMinimum<P>
17+
where
18+
P: Ord,
19+
{
20+
passband_set: PassbandSet<P>,
21+
passbands: [P; 2],
22+
name: String,
23+
description: String,
24+
}
25+
26+
impl<P> ColorOfMinimum<P>
27+
where
28+
P: PassbandTrait,
29+
{
30+
pub fn new(passbands: [P; 2]) -> Self {
31+
let set: BTreeSet<_> = passbands.clone().into();
32+
Self {
33+
passband_set: set.into(),
34+
name: format!("color_min_{}_{}", passbands[0].name(), passbands[1].name()),
35+
description: format!(
36+
"difference of minimum value magnitudes {}-{}",
37+
passbands[0].name(),
38+
passbands[1].name()
39+
),
40+
passbands,
41+
}
42+
}
43+
}
44+
45+
lazy_info!(
46+
COLOR_OF_MINIMUM_INFO,
47+
size: 1,
48+
min_ts_length: 1,
49+
t_required: false,
50+
m_required: true,
51+
w_required: false,
52+
sorting_required: false,
53+
variability_required: false,
54+
);
55+
56+
impl<P> EvaluatorInfoTrait for ColorOfMinimum<P>
57+
where
58+
P: Ord,
59+
{
60+
fn get_info(&self) -> &EvaluatorInfo {
61+
&COLOR_OF_MINIMUM_INFO
62+
}
63+
}
64+
65+
impl<P> FeatureNamesDescriptionsTrait for ColorOfMinimum<P>
66+
where
67+
P: Ord,
68+
{
69+
fn get_names(&self) -> Vec<&str> {
70+
vec![self.name.as_str()]
71+
}
72+
73+
fn get_descriptions(&self) -> Vec<&str> {
74+
vec![self.description.as_str()]
75+
}
76+
}
77+
78+
impl<P> MultiColorPassbandSetTrait<P> for ColorOfMinimum<P>
79+
where
80+
P: PassbandTrait,
81+
{
82+
fn get_passband_set(&self) -> &PassbandSet<P> {
83+
&self.passband_set
84+
}
85+
}
86+
87+
impl<P, T> MultiColorEvaluator<P, T> for ColorOfMinimum<P>
88+
where
89+
P: PassbandTrait,
90+
T: Float,
91+
{
92+
fn eval_multicolor_no_mcts_check(
93+
&self,
94+
mcts: &mut MultiColorTimeSeries<P, T>,
95+
) -> Result<Vec<T>, MultiColorEvaluatorError> {
96+
let mut minima = [T::zero(); 2];
97+
for ((_passband, mcts), minimum) in mcts
98+
.iter_matched_passbands_mut(self.passbands.iter())
99+
.zip(minima.iter_mut())
100+
{
101+
let mcts = mcts.expect("MultiColorTimeSeries must have all required passbands");
102+
*minimum = mcts.m.get_min()
103+
}
104+
Ok(vec![minima[0] - minima[1]])
105+
}
106+
}

src/multicolor/features/mod.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,8 @@
1+
mod color_of_maximum;
2+
pub use color_of_maximum::ColorOfMaximum;
3+
14
mod color_of_median;
25
pub use color_of_median::ColorOfMedian;
6+
7+
mod color_of_minimum;
8+
pub use color_of_minimum::ColorOfMinimum;

src/multicolor/multicolor_feature.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use crate::error::MultiColorEvaluatorError;
33
use crate::evaluator::{EvaluatorInfo, EvaluatorInfoTrait, FeatureNamesDescriptionsTrait};
44
use crate::feature::Feature;
55
use crate::float_trait::Float;
6-
use crate::multicolor::features::ColorOfMedian;
6+
use crate::multicolor::features::{ColorOfMaximum, ColorOfMedian, ColorOfMinimum};
77
use crate::multicolor::multicolor_evaluator::*;
88
use crate::multicolor::{MonochromeFeature, MultiColorExtractor};
99

@@ -28,7 +28,9 @@ where
2828
// Monochrome Features
2929
MonochromeFeature(MonochromeFeature<P, T, Feature<T>>),
3030
// Features
31+
ColorOfMaximum(ColorOfMaximum<P>),
3132
ColorOfMedian(ColorOfMedian<P>),
33+
ColorOfMinimum(ColorOfMinimum<P>),
3234
}
3335

3436
impl<P, T> MultiColorFeature<P, T>

0 commit comments

Comments
 (0)