Skip to content

Commit cdf6fd1

Browse files
committed
fix format
1 parent 35b5a57 commit cdf6fd1

10 files changed

Lines changed: 194 additions & 258 deletions

File tree

examples/generate_data.py

Lines changed: 11 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
for testing and demonstrating forecasting capabilities.
66
"""
77

8-
98
import numpy as np
109

1110

@@ -14,7 +13,7 @@ def generate_linear_trend_series(
1413
context_length: int = 256,
1514
trend_slope: float = 0.05,
1615
noise_std: float = 0.5,
17-
seed: int | None = None
16+
seed: int | None = None,
1817
) -> np.ndarray:
1918
"""
2019
Generate simple time series with linear trend and Gaussian noise.
@@ -59,7 +58,7 @@ def generate_correlated_multi_series(
5958
seasonal_amplitude: float = 2.0,
6059
trend_slope: float = 0.02,
6160
noise_std: float = 0.3,
62-
seed: int | None = None
61+
seed: int | None = None,
6362
) -> np.ndarray:
6463
"""
6564
Generate two correlated time series with seasonal patterns.
@@ -105,10 +104,7 @@ def generate_correlated_multi_series(
105104
noise2 = np.random.normal(0, noise_std, size=(batch_size, context_length))
106105

107106
# Mix correlated and independent components
108-
series2 = (
109-
correlation * series1 +
110-
(1 - correlation) * (independent_base[np.newaxis, :] + noise2)
111-
)
107+
series2 = correlation * series1 + (1 - correlation) * (independent_base[np.newaxis, :] + noise2)
112108

113109
# Stack into (batch_size, context_length, 2)
114110
multi_series = np.stack([series1, series2], axis=-1)
@@ -122,7 +118,7 @@ def generate_heavy_payload(
122118
num_features: int = 1,
123119
pattern_type: str = "mixed",
124120
noise_std: float = 0.4,
125-
seed: int | None = None
121+
seed: int | None = None,
126122
) -> np.ndarray:
127123
"""
128124
Generate large batch of time series for stress testing and performance evaluation.
@@ -208,31 +204,17 @@ def generate_test_suite(seed: int = 42) -> dict[str, np.ndarray]:
208204
"""
209205
return {
210206
# Simple patterns
211-
"linear_trend_single": generate_linear_trend_series(
212-
batch_size=1, context_length=256, seed=seed
213-
),
214-
"linear_trend_batch": generate_linear_trend_series(
215-
batch_size=16, context_length=256, seed=seed
216-
),
217-
207+
"linear_trend_single": generate_linear_trend_series(batch_size=1, context_length=256, seed=seed),
208+
"linear_trend_batch": generate_linear_trend_series(batch_size=16, context_length=256, seed=seed),
218209
# Correlated multi-series
219-
"correlated_multi_single": generate_correlated_multi_series(
220-
batch_size=1, context_length=256, seed=seed
221-
),
222-
"correlated_multi_batch": generate_correlated_multi_series(
223-
batch_size=16, context_length=256, seed=seed
224-
),
225-
210+
"correlated_multi_single": generate_correlated_multi_series(batch_size=1, context_length=256, seed=seed),
211+
"correlated_multi_batch": generate_correlated_multi_series(batch_size=16, context_length=256, seed=seed),
226212
# Heavy payloads
227-
"heavy_mixed": generate_heavy_payload(
228-
batch_size=100, context_length=2048, pattern_type="mixed", seed=seed
229-
),
213+
"heavy_mixed": generate_heavy_payload(batch_size=100, context_length=2048, pattern_type="mixed", seed=seed),
230214
"heavy_seasonal": generate_heavy_payload(
231215
batch_size=100, context_length=2048, pattern_type="seasonal", seed=seed
232216
),
233-
"heavy_trend": generate_heavy_payload(
234-
batch_size=100, context_length=2048, pattern_type="trend", seed=seed
235-
),
217+
"heavy_trend": generate_heavy_payload(batch_size=100, context_length=2048, pattern_type="trend", seed=seed),
236218
}
237219

238220

@@ -265,4 +247,4 @@ def generate_test_suite(seed: int = 42) -> dict[str, np.ndarray]:
265247
test_suite = generate_test_suite(seed=42)
266248
print(f"Generated {len(test_suite)} datasets:")
267249
for name, data in test_suite.items():
268-
print(f" {name}: {data.shape}")
250+
print(f" {name}: {data.shape}")

examples/model_comparison_simple.ipynb

Lines changed: 112 additions & 87 deletions
Large diffs are not rendered by default.

faim_sdk/client.py

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
""" FAIM SDK client for time-series forecasting.
1+
"""FAIM SDK client for time-series forecasting.
22
33
Provides high-level, type-safe API with automatic serialization, error handling,
44
and observability.
@@ -197,10 +197,7 @@ def _reshape_univariate_response(
197197
if response.samples is not None:
198198
modified_response.samples = response.samples
199199

200-
logger.debug(
201-
f"Reshaped univariate response: "
202-
f"original_batch={original_batch_size}, features={num_features}"
203-
)
200+
logger.debug(f"Reshaped univariate response: original_batch={original_batch_size}, features={num_features}")
204201

205202
return modified_response
206203

@@ -465,9 +462,7 @@ def forecast(self, request: ForecastRequest) -> ForecastResponse:
465462
# If univariate transformation was applied, reshape response back
466463
if transform_shape_info is not None:
467464
original_batch_size, num_features = transform_shape_info
468-
forecast_response = _reshape_univariate_response(
469-
forecast_response, original_batch_size, num_features
470-
)
465+
forecast_response = _reshape_univariate_response(forecast_response, original_batch_size, num_features)
471466

472467
logger.info(f"Forecast successful: {forecast_response}")
473468
return forecast_response
@@ -651,9 +646,7 @@ async def forecast_async(self, request: ForecastRequest) -> ForecastResponse:
651646
# If univariate transformation was applied, reshape response back
652647
if transform_shape_info is not None:
653648
original_batch_size, num_features = transform_shape_info
654-
forecast_response = _reshape_univariate_response(
655-
forecast_response, original_batch_size, num_features
656-
)
649+
forecast_response = _reshape_univariate_response(forecast_response, original_batch_size, num_features)
657650

658651
logger.info(f"Async forecast successful: {forecast_response}")
659652
return forecast_response

faim_sdk/eval/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,4 +75,4 @@
7575
"crps_from_quantiles",
7676
# Visualization
7777
"plot_forecast",
78-
]
78+
]

faim_sdk/eval/metrics.py

Lines changed: 18 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -122,17 +122,11 @@ def mse(
122122

123123
# Shape validation
124124
if y_true.ndim != 3:
125-
raise ValueError(
126-
f"y_true must be 3-dimensional (batch_size, horizon, features), got shape {y_true.shape}"
127-
)
125+
raise ValueError(f"y_true must be 3-dimensional (batch_size, horizon, features), got shape {y_true.shape}")
128126
if y_pred.ndim != 3:
129-
raise ValueError(
130-
f"y_pred must be 3-dimensional (batch_size, horizon, features), got shape {y_pred.shape}"
131-
)
127+
raise ValueError(f"y_pred must be 3-dimensional (batch_size, horizon, features), got shape {y_pred.shape}")
132128
if y_true.shape != y_pred.shape:
133-
raise ValueError(
134-
f"y_true and y_pred must have the same shape, got {y_true.shape} and {y_pred.shape}"
135-
)
129+
raise ValueError(f"y_true and y_pred must have the same shape, got {y_true.shape} and {y_pred.shape}")
136130

137131
# Empty validation
138132
if y_true.size == 0:
@@ -215,17 +209,11 @@ def mae(
215209

216210
# Shape validation
217211
if y_true.ndim != 3:
218-
raise ValueError(
219-
f"y_true must be 3-dimensional (batch_size, horizon, features), got shape {y_true.shape}"
220-
)
212+
raise ValueError(f"y_true must be 3-dimensional (batch_size, horizon, features), got shape {y_true.shape}")
221213
if y_pred.ndim != 3:
222-
raise ValueError(
223-
f"y_pred must be 3-dimensional (batch_size, horizon, features), got shape {y_pred.shape}"
224-
)
214+
raise ValueError(f"y_pred must be 3-dimensional (batch_size, horizon, features), got shape {y_pred.shape}")
225215
if y_true.shape != y_pred.shape:
226-
raise ValueError(
227-
f"y_true and y_pred must have the same shape, got {y_true.shape} and {y_pred.shape}"
228-
)
216+
raise ValueError(f"y_true and y_pred must have the same shape, got {y_true.shape} and {y_pred.shape}")
229217

230218
# Empty validation
231219
if y_true.size == 0:
@@ -341,43 +329,33 @@ def mase(
341329

342330
# Shape validation
343331
if y_true.ndim != 3:
344-
raise ValueError(
345-
f"y_true must be 3-dimensional (batch_size, horizon, features), got shape {y_true.shape}"
346-
)
332+
raise ValueError(f"y_true must be 3-dimensional (batch_size, horizon, features), got shape {y_true.shape}")
347333
if y_pred.ndim != 3:
348-
raise ValueError(
349-
f"y_pred must be 3-dimensional (batch_size, horizon, features), got shape {y_pred.shape}"
350-
)
334+
raise ValueError(f"y_pred must be 3-dimensional (batch_size, horizon, features), got shape {y_pred.shape}")
351335
if y_train.ndim != 3:
352336
raise ValueError(
353337
f"y_train must be 3-dimensional (batch_size, train_length, features), got shape {y_train.shape}"
354338
)
355339

356340
if y_true.shape != y_pred.shape:
357-
raise ValueError(
358-
f"y_true and y_pred must have the same shape, got {y_true.shape} and {y_pred.shape}"
359-
)
341+
raise ValueError(f"y_true and y_pred must have the same shape, got {y_true.shape} and {y_pred.shape}")
360342

361343
batch_size_true, _, features_true = y_true.shape
362344
batch_size_train, train_length, features_train = y_train.shape
363345

364346
if batch_size_true != batch_size_train:
365347
raise ValueError(
366-
f"Batch size mismatch: y_true has {batch_size_true} samples, "
367-
f"y_train has {batch_size_train} samples"
348+
f"Batch size mismatch: y_true has {batch_size_true} samples, y_train has {batch_size_train} samples"
368349
)
369350

370351
if features_true != features_train:
371352
raise ValueError(
372-
f"Feature count mismatch: y_true has {features_true} features, "
373-
f"y_train has {features_train} features"
353+
f"Feature count mismatch: y_true has {features_true} features, y_train has {features_train} features"
374354
)
375355

376356
# Training data length validation
377357
if train_length < 2:
378-
raise ValueError(
379-
f"y_train must have at least 2 time steps for naive baseline, got {train_length}"
380-
)
358+
raise ValueError(f"y_train must have at least 2 time steps for naive baseline, got {train_length}")
381359

382360
# Empty validation
383361
if y_true.size == 0:
@@ -551,9 +529,7 @@ def crps_from_quantiles(
551529

552530
# Shape validation
553531
if y_true.ndim != 3:
554-
raise ValueError(
555-
f"y_true must be 3-dimensional (batch_size, horizon, features), got shape {y_true.shape}"
556-
)
532+
raise ValueError(f"y_true must be 3-dimensional (batch_size, horizon, features), got shape {y_true.shape}")
557533
if quantile_preds.ndim != 3:
558534
raise ValueError(
559535
f"quantile_preds must be 3-dimensional (batch_size, horizon, num_quantiles), "
@@ -565,29 +541,22 @@ def crps_from_quantiles(
565541

566542
if batch_size_true != batch_size_pred:
567543
raise ValueError(
568-
f"Batch size mismatch: y_true has {batch_size_true} samples, "
569-
f"quantile_preds has {batch_size_pred} samples"
544+
f"Batch size mismatch: y_true has {batch_size_true} samples, quantile_preds has {batch_size_pred} samples"
570545
)
571546
if horizon_true != horizon_pred:
572-
raise ValueError(
573-
f"Horizon mismatch: y_true has {horizon_true} steps, "
574-
f"quantile_preds has {horizon_pred} steps"
575-
)
547+
raise ValueError(f"Horizon mismatch: y_true has {horizon_true} steps, quantile_preds has {horizon_pred} steps")
576548

577549
# Quantile levels validation
578550
if len(quantile_levels) != num_quantiles:
579551
raise ValueError(
580-
f"quantile_levels length ({len(quantile_levels)}) must match "
581-
f"num_quantiles dimension ({num_quantiles})"
552+
f"quantile_levels length ({len(quantile_levels)}) must match num_quantiles dimension ({num_quantiles})"
582553
)
583554

584555
if not all(0.0 <= q <= 1.0 for q in quantile_levels):
585556
raise ValueError(f"quantile_levels must be in [0.0, 1.0], got {quantile_levels}")
586557

587558
if quantile_levels != sorted(quantile_levels):
588-
raise ValueError(
589-
f"quantile_levels must be sorted in ascending order, got {quantile_levels}"
590-
)
559+
raise ValueError(f"quantile_levels must be sorted in ascending order, got {quantile_levels}")
591560

592561
# Empty validation
593562
if y_true.size == 0:
@@ -656,4 +625,4 @@ def crps_from_quantiles(
656625
# Average over horizon, keep batch dimension
657626
return np.mean(crps_values, axis=1)
658627
else:
659-
raise ValueError(f"reduction must be 'mean' or 'none', got '{reduction}'")
628+
raise ValueError(f"reduction must be 'mean' or 'none', got '{reduction}'")

faim_sdk/eval/visualization.py

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -236,14 +236,10 @@ def plot_forecast(
236236
if test_data is not None:
237237
test_horizon, test_features = test_data.shape
238238
if test_horizon != horizon:
239-
raise ValueError(
240-
f"Horizon mismatch: forecast has {horizon} steps, "
241-
f"test_data has {test_horizon} steps"
242-
)
239+
raise ValueError(f"Horizon mismatch: forecast has {horizon} steps, test_data has {test_horizon} steps")
243240
if test_features != num_features:
244241
raise ValueError(
245-
f"Feature count mismatch: forecast has {num_features} features, "
246-
f"test_data has {test_features} features"
242+
f"Feature count mismatch: forecast has {num_features} features, test_data has {test_features} features"
247243
)
248244

249245
# Validate feature count for single plot
@@ -258,12 +254,11 @@ def plot_forecast(
258254
if num_features == 1:
259255
feature_names = ["Series"]
260256
else:
261-
feature_names = [f"Feature {i+1}" for i in range(num_features)]
257+
feature_names = [f"Feature {i + 1}" for i in range(num_features)]
262258
else:
263259
if len(feature_names) != num_features:
264260
raise ValueError(
265-
f"feature_names length ({len(feature_names)}) must match "
266-
f"number of features ({num_features})"
261+
f"feature_names length ({len(feature_names)}) must match number of features ({num_features})"
267262
)
268263

269264
# Create time indices
@@ -397,4 +392,4 @@ def plot_forecast(
397392
if save_path is not None:
398393
fig.savefig(save_path, dpi=300, bbox_inches="tight")
399394

400-
return fig, axes
395+
return fig, axes

faim_sdk/models.py

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -238,9 +238,7 @@ def __post_init__(self) -> None:
238238
f"got prediction_type='{self.prediction_type}'"
239239
)
240240
if self.output_type == "point" and self.prediction_type == "quantile":
241-
raise ValueError(
242-
"output_type='point' conflicts with prediction_type='quantile'"
243-
)
241+
raise ValueError("output_type='point' conflicts with prediction_type='quantile'")
244242

245243
def to_arrays_and_metadata(self) -> tuple[dict[str, np.ndarray], dict[str, Any]]:
246244
"""Convert FlowState request to Arrow format.
@@ -330,8 +328,4 @@ def __repr__(self) -> str:
330328

331329
outputs_str = ", ".join(outputs) if outputs else "None"
332330

333-
return (
334-
f"ForecastResponse("
335-
f"outputs=[{outputs_str}], "
336-
f"metadata={self.metadata})"
337-
)
331+
return f"ForecastResponse(outputs=[{outputs_str}], metadata={self.metadata})"

tests/unit/test_client.py

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -690,12 +690,7 @@ def test_flowstate_multivariate_quantile_forecast(self, mock_post):
690690
mock_post.return_value = mock_response
691691

692692
client = ForecastClient(base_url="https://api.example.com")
693-
request = FlowStateForecastRequest(
694-
x=data,
695-
horizon=8,
696-
prediction_type="quantile",
697-
output_type="quantiles"
698-
)
693+
request = FlowStateForecastRequest(x=data, horizon=8, prediction_type="quantile", output_type="quantiles")
699694

700695
# Execute with warning capture
701696
with pytest.warns(UserWarning, match="FlowState model only supports univariate forecasting"):

0 commit comments

Comments
 (0)