@@ -156,3 +156,149 @@ def test_plotter_from_df_missing_columns_raises(self):
156156 df_missing = self .df .drop (columns = ["fitness" ])
157157 with self .assertRaises (KeyError ):
158158 plot_from_df (df_missing , "avg_err" , "fitness" , {})
159+
160+ def test_model_selector (self ):
161+ from ..utils import select_models
162+ models = select_models ()
163+ self .assertTrue (len (models ) > 0 )
164+
165+ # Use MinMaxAnomalyDetector as a reference for capability-based selection
166+ from ..anomaly_detectors .naive .minmax import MinMaxAnomalyDetector
167+ requested_capabilities = {
168+ "training" : {
169+ "mode" : None ,
170+ "update" : False
171+ },
172+ "inference" : {
173+ "streaming" : False ,
174+ "dependency" : "series" ,
175+ "granularity" : "point-labels"
176+ },
177+ "data" : {
178+ "dimensionality" : "univariate-single" ,
179+ "sampling" : "irregular"
180+ }
181+ }
182+
183+ selected = select_models (requested_capabilities )
184+ self .assertIn (MinMaxAnomalyDetector , selected )
185+
186+ def test_model_selector_no_filter_returns_all (self ):
187+ from ..utils import select_models
188+ from ..anomaly_detectors import (
189+ MinMaxAnomalyDetector , ZScoreAnomalyDetector ,
190+ COMAnomalyDetector , HARAnomalyDetector , NHARAnomalyDetector ,
191+ IFSOMAnomalyDetector , LinearRegressionAnomalyDetector , LSTMAnomalyDetector ,
192+ )
193+ all_expected = {
194+ MinMaxAnomalyDetector , ZScoreAnomalyDetector ,
195+ COMAnomalyDetector , HARAnomalyDetector , NHARAnomalyDetector ,
196+ IFSOMAnomalyDetector , LinearRegressionAnomalyDetector , LSTMAnomalyDetector ,
197+ }
198+ models = select_models ()
199+ self .assertEqual (set (models ), all_expected )
200+
201+ def test_model_selector_by_training_mode_none (self ):
202+ from ..utils import select_models
203+ from ..anomaly_detectors import MinMaxAnomalyDetector , ZScoreAnomalyDetector
204+ selected = select_models ({"training" : {"mode" : None }})
205+ self .assertEqual (set (selected ), {MinMaxAnomalyDetector , ZScoreAnomalyDetector })
206+
207+ def test_model_selector_by_training_mode_unsupervised (self ):
208+ from ..utils import select_models
209+ from ..anomaly_detectors import (
210+ COMAnomalyDetector , HARAnomalyDetector , NHARAnomalyDetector ,
211+ IFSOMAnomalyDetector ,
212+ )
213+ selected = select_models ({"training" : {"mode" : "unsupervised" }})
214+ self .assertEqual (set (selected ), {
215+ COMAnomalyDetector , HARAnomalyDetector , NHARAnomalyDetector ,
216+ IFSOMAnomalyDetector ,
217+ })
218+
219+ def test_model_selector_by_training_mode_semi_supervised (self ):
220+ from ..utils import select_models
221+ from ..anomaly_detectors import LinearRegressionAnomalyDetector , LSTMAnomalyDetector
222+ selected = select_models ({"training" : {"mode" : "semi-supervised" }})
223+ self .assertEqual (set (selected ), {LinearRegressionAnomalyDetector , LSTMAnomalyDetector })
224+
225+ def test_model_selector_by_inference_dependency_window (self ):
226+ from ..utils import select_models
227+ from ..anomaly_detectors import LinearRegressionAnomalyDetector , LSTMAnomalyDetector
228+ selected = select_models ({"inference" : {"dependency" : "window" }})
229+ self .assertEqual (set (selected ), {LinearRegressionAnomalyDetector , LSTMAnomalyDetector })
230+
231+ def test_model_selector_by_inference_granularity_series (self ):
232+ from ..utils import select_models
233+ from ..anomaly_detectors import IFSOMAnomalyDetector
234+ selected = select_models ({"inference" : {"granularity" : "series" }})
235+ self .assertEqual (set (selected ), {IFSOMAnomalyDetector })
236+
237+ def test_model_selector_by_sampling_irregular (self ):
238+ from ..utils import select_models
239+ from ..anomaly_detectors import MinMaxAnomalyDetector , ZScoreAnomalyDetector
240+ selected = select_models ({"data" : {"sampling" : "irregular" }})
241+ self .assertEqual (set (selected ), {MinMaxAnomalyDetector , ZScoreAnomalyDetector })
242+
243+ def test_model_selector_by_dimensionality_scalar (self ):
244+ """Requesting a single dimensionality value matches models that include it in their list."""
245+ from ..utils import select_models
246+ from ..anomaly_detectors import (
247+ MinMaxAnomalyDetector , COMAnomalyDetector , HARAnomalyDetector ,
248+ NHARAnomalyDetector , IFSOMAnomalyDetector ,
249+ )
250+ selected = select_models ({"data" : {"dimensionality" : "univariate-multi" }})
251+ self .assertEqual (set (selected ), {
252+ MinMaxAnomalyDetector , COMAnomalyDetector , HARAnomalyDetector ,
253+ NHARAnomalyDetector , IFSOMAnomalyDetector ,
254+ })
255+
256+ def test_model_selector_by_dimensionality_list (self ):
257+ """Requesting a list of dimensionalities matches models supporting ALL of them (subset check)."""
258+ from ..utils import select_models
259+ from ..anomaly_detectors import (
260+ MinMaxAnomalyDetector , COMAnomalyDetector , HARAnomalyDetector ,
261+ NHARAnomalyDetector ,
262+ )
263+ selected = select_models ({"data" : {"dimensionality" : ["univariate-multi" , "multivariate-single" ]}})
264+ self .assertEqual (set (selected ), {
265+ MinMaxAnomalyDetector , COMAnomalyDetector , HARAnomalyDetector ,
266+ NHARAnomalyDetector ,
267+ })
268+
269+ def test_model_selector_multiple_sections (self ):
270+ """Filtering across multiple capability sections at once."""
271+ from ..utils import select_models
272+ from ..anomaly_detectors import MinMaxAnomalyDetector , ZScoreAnomalyDetector
273+ selected = select_models ({
274+ "training" : {"mode" : None },
275+ "data" : {"sampling" : "irregular" },
276+ })
277+ self .assertEqual (set (selected ), {MinMaxAnomalyDetector , ZScoreAnomalyDetector })
278+
279+ def test_model_selector_multiple_fields_narrow (self ):
280+ """Combining multiple fields to narrow down to a unique model."""
281+ from ..utils import select_models
282+ from ..anomaly_detectors import IFSOMAnomalyDetector
283+ selected = select_models ({
284+ "training" : {"mode" : "unsupervised" },
285+ "inference" : {"granularity" : "series" },
286+ })
287+ self .assertEqual (set (selected ), {IFSOMAnomalyDetector })
288+
289+ def test_model_selector_no_match (self ):
290+ """Requesting a combination no model satisfies returns an empty list."""
291+ from ..utils import select_models
292+ selected = select_models ({
293+ "training" : {"mode" : "supervised" },
294+ })
295+ self .assertEqual (selected , [])
296+
297+ def test_model_selector_no_match_contradictory (self ):
298+ """Contradictory constraints across sections return empty."""
299+ from ..utils import select_models
300+ selected = select_models ({
301+ "training" : {"mode" : None },
302+ "data" : {"sampling" : "regular" },
303+ })
304+ self .assertEqual (selected , [])
0 commit comments