dfm-python 0.5.55__py3-none-any.whl → 0.5.57__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. dfm_python/__init__.py +19 -49
  2. dfm_python/config/__init__.py +7 -12
  3. dfm_python/config/adapter.py +63 -7
  4. dfm_python/config/constants.py +149 -10
  5. dfm_python/config/schema/__init__.py +8 -6
  6. dfm_python/config/schema/block.py +61 -3
  7. dfm_python/config/schema/model.py +40 -11
  8. dfm_python/config/schema/params.py +279 -0
  9. dfm_python/config/schema/results.py +121 -92
  10. dfm_python/config/types.py +57 -28
  11. dfm_python/dataset/__init__.py +8 -47
  12. dfm_python/dataset/ddfm_dataset.py +393 -0
  13. dfm_python/{datamodule/dfm_dm.py → dataset/dfm_dataset.py} +263 -92
  14. dfm_python/dataset/time.py +97 -0
  15. dfm_python/decoder/__init__.py +3 -1
  16. dfm_python/decoder/base.py +78 -0
  17. dfm_python/decoder/linear.py +63 -59
  18. dfm_python/decoder/mlp.py +117 -126
  19. dfm_python/encoder/__init__.py +9 -9
  20. dfm_python/encoder/pca.py +6 -5
  21. dfm_python/encoder/simple_autoencoder.py +292 -0
  22. dfm_python/functional/__init__.py +7 -9
  23. dfm_python/functional/dfm_block.py +65 -14
  24. dfm_python/functional/em.py +580 -223
  25. dfm_python/logger/__init__.py +21 -11
  26. dfm_python/logger/inference_logger.py +41 -29
  27. dfm_python/logger/logger.py +129 -5
  28. dfm_python/logger/train_logger.py +81 -68
  29. dfm_python/models/__init__.py +2 -10
  30. dfm_python/models/base.py +51 -230
  31. dfm_python/models/ddfm.py +809 -1715
  32. dfm_python/models/dfm.py +576 -384
  33. dfm_python/numeric/estimator.py +281 -52
  34. dfm_python/numeric/stability.py +133 -167
  35. dfm_python/numeric/statistic.py +353 -0
  36. dfm_python/numeric/tent.py +16 -6
  37. dfm_python/numeric/validator.py +159 -8
  38. dfm_python/ssm/__init__.py +13 -3
  39. dfm_python/ssm/kalman.py +274 -142
  40. dfm_python/utils/__init__.py +20 -38
  41. dfm_python/utils/checkpoint.py +295 -0
  42. dfm_python/utils/helper.py +62 -152
  43. dfm_python/utils/loss.py +100 -0
  44. dfm_python/utils/misc.py +73 -150
  45. dfm_python/utils/validation.py +4 -71
  46. {dfm_python-0.5.55.dist-info → dfm_python-0.5.57.dist-info}/METADATA +4 -5
  47. dfm_python-0.5.57.dist-info/RECORD +52 -0
  48. dfm_python/datamodule/__init__.py +0 -31
  49. dfm_python/datamodule/base.py +0 -618
  50. dfm_python/datamodule/ddfm_dm.py +0 -276
  51. dfm_python/datamodule/kdfm_dm.py +0 -180
  52. dfm_python/dataset/dataloader.py +0 -142
  53. dfm_python/dataset/dataset.py +0 -158
  54. dfm_python/dataset/process.py +0 -435
  55. dfm_python/encoder/simple_encoder.py +0 -474
  56. dfm_python/encoder/variational_encoder.py +0 -0
  57. dfm_python/functional/irf.py +0 -305
  58. dfm_python/functional/krylov.py +0 -124
  59. dfm_python/models/kdfm.py +0 -1968
  60. dfm_python/ssm/arma.py +0 -0
  61. dfm_python/ssm/companion.py +0 -995
  62. dfm_python/ssm/structural.py +0 -298
  63. dfm_python/trainer/__init__.py +0 -683
  64. dfm_python/trainer/ddfm.py +0 -656
  65. dfm_python/trainer/dfm.py +0 -154
  66. dfm_python/trainer/kdfm.py +0 -137
  67. dfm_python/utils/common.py +0 -403
  68. dfm_python/utils/tensor_utils.py +0 -199
  69. dfm_python-0.5.55.dist-info/RECORD +0 -66
  70. dfm_python-0.5.55.dist-info/licenses/LICENSE +0 -21
  71. {dfm_python-0.5.55.dist-info → dfm_python-0.5.57.dist-info}/WHEEL +0 -0
dfm_python/__init__.py CHANGED
@@ -23,40 +23,36 @@ Key Features:
23
23
  - Robust handling of missing data (internal spline interpolation)
24
24
  - Automatic standardization and data clipping
25
25
 
26
- Example (Standard Lightning Pattern):
27
- >>> from dfm_python import DFM, DFMDataModule, DFMTrainer
26
+ Example:
27
+ >>> from dfm_python import DFM, DFMDataset
28
28
  >>> import pandas as pd
29
29
  >>>
30
30
  >>> # Step 1: Load and preprocess data
31
31
  >>> df = pd.read_csv('data/your_data.csv')
32
32
  >>> df_processed = df[[col for col in df.columns if col != 'date']]
33
33
  >>>
34
- >>> # Step 2: Create DataModule
35
- >>> dm = DFMDataModule(config_path='config/default.yaml', data=df_processed)
36
- >>> dm.setup()
34
+ >>> # Step 2: Create Dataset
35
+ >>> dataset = DFMDataset(config_path='config/default.yaml', data=df_processed)
37
36
  >>>
38
37
  >>> # Step 3: Create model and load config
39
38
  >>> model = DFM()
40
39
  >>> model.load_config('config/default.yaml')
41
40
  >>>
42
- >>> # Step 4: Create trainer and fit (standard Lightning pattern)
43
- >>> trainer = DFMTrainer(max_epochs=100) # DEFAULT_MAX_EPOCHS
44
- >>> trainer.fit(model, dm)
41
+ >>> # Step 4: Fit model
42
+ >>> model.fit(X=dataset.get_processed_data(), dataset=dataset)
45
43
  >>>
46
44
  >>> # Step 5: Predict
47
45
  >>> Xf, Zf = model.predict(horizon=6)
48
46
  >>>
49
- >>> # Or use DDFM (same pattern)
50
- >>> from dfm_python import DDFM, DDFMTrainer
47
+ >>> # Or use DDFM
48
+ >>> from dfm_python import DDFM, DDFMDataset
51
49
  >>>
52
- >>> dm_ddfm = DFMDataModule(config_path='config/default.yaml', data=df_processed)
53
- >>> dm_ddfm.setup()
50
+ >>> dataset_ddfm = DDFMDataset(config_path='config/default.yaml', data=df_processed)
54
51
  >>>
55
52
  >>> ddfm_model = DDFM(encoder_layers=[64, 32], num_factors=2)
56
53
  >>> ddfm_model.load_config('config/default.yaml')
57
54
  >>>
58
- >>> trainer_ddfm = DDFMTrainer(max_epochs=100) # DEFAULT_MAX_EPOCHS
59
- >>> trainer_ddfm.fit(ddfm_model, dm_ddfm)
55
+ >>> ddfm_model.train(dataset=dataset_ddfm)
60
56
  >>> Xf, Zf = ddfm_model.predict(horizon=6)
61
57
 
62
58
  Note: DFMConfig uses frequency dict to specify series (column names -> frequencies).
@@ -65,7 +61,7 @@ Note: DFMConfig uses frequency dict to specify series (column names -> frequenci
65
61
  For detailed documentation, see the README.md file and the tutorial notebooks/scripts.
66
62
  """
67
63
 
68
- __version__ = "0.5.55"
64
+ __version__ = "0.5.56"
69
65
 
70
66
  # ============================================================================
71
67
  # PUBLIC API DEFINITION
@@ -92,20 +88,15 @@ from .config import (
92
88
  from .config import DFMConfig
93
89
 
94
90
  # Results
95
- from .config import DFMResult, DDFMResult, KDFMResult, BaseResult
91
+ from .config import DFMResult, DDFMResult, BaseResult
96
92
 
97
93
  # Utilities (from utils/ subpackage)
98
94
  from .utils.metric import calculate_rmse
99
95
 
100
- # DataModule classes (includes both Lightning and custom implementations)
96
+ # Dataset classes
101
97
  # Users can import these directly from dfm_python
102
- from .datamodule import (
103
- DFMDataModule,
104
- DDFMDataModule, # DDFM-specific DataModule
105
- KDFMDataModule, # KDFM-specific DataModule
106
- DDFMDataset, # DDFM Dataset class (usually not needed directly)
107
- KDFMDataset, # KDFM Dataset class (usually not needed directly)
108
- )
98
+ from .dataset.dfm_dataset import DFMDataset
99
+ from .dataset.ddfm_dataset import DDFMDataset
109
100
 
110
101
  # Model implementations
111
102
  from .models.base import BaseFactorModel
@@ -114,9 +105,6 @@ from .models.dfm import DFM
114
105
  # DDFM high-level API (PyTorch is mandatory)
115
106
  from .models.ddfm import DDFM
116
107
 
117
- # KDFM high-level API
118
- from .models.kdfm import KDFM
119
-
120
108
  __all__ = [
121
109
  # Core classes
122
110
  'DFM',
@@ -126,7 +114,7 @@ __all__ = [
126
114
  'ConfigSource', 'YamlSource',
127
115
  'make_config_source',
128
116
  # Low-level API (functional interface - advanced usage)
129
- 'BaseResult', 'DFMResult', 'DDFMResult', 'KDFMResult', 'calculate_rmse',
117
+ 'BaseResult', 'DFMResult', 'DDFMResult', 'calculate_rmse',
130
118
  ]
131
119
 
132
120
  # DDFM high-level API (PyTorch is mandatory)
@@ -134,27 +122,9 @@ __all__.extend([
134
122
  'DDFM', # High-level API class
135
123
  ])
136
124
 
137
- # KDFM high-level API
138
- __all__.extend([
139
- 'KDFM', # High-level API class
140
- ])
141
-
142
- # Lightning modules (mandatory dependency)
125
+ # Dataset classes
143
126
  __all__.extend([
144
- 'DFMDataModule',
145
- 'DDFMDataModule', # DDFM-specific DataModule
146
- 'KDFMDataModule', # KDFM-specific DataModule
147
- 'DDFMDataset', # DDFM Dataset class (usually not needed directly)
148
- 'KDFMDataset', # KDFM Dataset class (usually not needed directly)
127
+ 'DFMDataset', # DFM Dataset class
128
+ 'DDFMDataset', # DDFM Dataset class
149
129
  ])
150
130
 
151
- # Trainer classes (mandatory dependency)
152
- from .trainer import DFMTrainer, DDFMTrainer, KDFMTrainer
153
-
154
- __all__.extend([
155
- 'DFMTrainer',
156
- 'DDFMTrainer',
157
- 'KDFMTrainer',
158
- ])
159
-
160
-
@@ -8,8 +8,9 @@ Note: Series are specified via frequency dict mapping column names to frequencie
8
8
  """
9
9
 
10
10
  from .schema import (
11
- BaseModelConfig, DFMConfig, DDFMConfig, KDFMConfig,
12
- BaseResult, DFMResult, DDFMResult, KDFMResult, FitParams,
11
+ BaseModelConfig, DFMConfig, DDFMConfig,
12
+ BaseResult, DFMResult, DDFMResult,
13
+ DFMStateSpaceParams, DDFMStateSpaceParams,
13
14
  )
14
15
  # DEFAULT_BLOCK_NAME is imported lazily where needed to avoid circular imports
15
16
  from .constants import (
@@ -45,8 +46,6 @@ from .types import (
45
46
  ForecastResult,
46
47
  CoefficientMatrix,
47
48
  CovarianceMatrix,
48
- IRFArray,
49
- CompanionMatrix,
50
49
  SeriesID,
51
50
  Frequency,
52
51
  DatasetName,
@@ -57,7 +56,6 @@ from .types import (
57
56
  ResultDict,
58
57
  ForecastDict,
59
58
  MetricsDict,
60
- IRFResultDict,
61
59
  CheckpointDict,
62
60
  ConfigDict,
63
61
  Device,
@@ -105,11 +103,11 @@ __all__ = [
105
103
  'BaseModelConfig', 'BaseResult',
106
104
  # 'DEFAULT_BLOCK_NAME', # Removed to avoid circular import - import directly from functional.dfm_block
107
105
  # Model-specific configs (from schema.py)
108
- 'DFMConfig', 'DDFMConfig', 'KDFMConfig',
109
- # Parameter overrides
110
- 'FitParams',
106
+ 'DFMConfig', 'DDFMConfig',
107
+ # State-space parameters
108
+ 'DFMStateSpaceParams', 'DDFMStateSpaceParams',
111
109
  # Model-specific results (from results.py)
112
- 'DFMResult', 'DDFMResult', 'KDFMResult',
110
+ 'DFMResult', 'DDFMResult',
113
111
  # Utilities
114
112
  'validate_frequency',
115
113
  # IO
@@ -137,8 +135,6 @@ __all__ = [
137
135
  'ForecastResult',
138
136
  'CoefficientMatrix',
139
137
  'CovarianceMatrix',
140
- 'IRFArray',
141
- 'CompanionMatrix',
142
138
  'SeriesID',
143
139
  'Frequency',
144
140
  'DatasetName',
@@ -149,7 +145,6 @@ __all__ = [
149
145
  'ResultDict',
150
146
  'ForecastDict',
151
147
  'MetricsDict',
152
- 'IRFResultDict',
153
148
  'CheckpointDict',
154
149
  'ConfigDict',
155
150
  'Device',
@@ -118,7 +118,12 @@ def _extract_frequency_dict(
118
118
  data: Dict[str, Any],
119
119
  clock: str = DEFAULT_CLOCK_FREQUENCY
120
120
  ) -> Optional[Dict[str, str]]:
121
- """Extract frequency dict from data, handling both new API and legacy formats.
121
+ """Extract frequency dict from data, handling multiple formats.
122
+
123
+ Supports:
124
+ 1. Grouped format: {'w': [series1, series2, ...], 'm': [series3, ...]}
125
+ 2. Individual format: {'series1': 'w', 'series2': 'm', ...}
126
+ 3. Legacy format: {'series': [{'series_id': ..., 'frequency': ...}, ...]}
122
127
 
123
128
  Parameters
124
129
  ----------
@@ -132,12 +137,63 @@ def _extract_frequency_dict(
132
137
  Optional[Dict[str, str]]
133
138
  Frequency dict mapping column names to frequencies, or None if not found
134
139
  """
135
- if 'frequency' in data:
136
- # New API: frequency dict directly
137
- return data['frequency']
138
- elif 'series' in data:
139
- # Legacy: convert series list/dict to frequency dict
140
- return _convert_series_to_frequency_dict(data['series'], clock)
140
+ if 'frequency' not in data:
141
+ # Legacy: check for 'series' key
142
+ if 'series' in data:
143
+ return _convert_series_to_frequency_dict(data['series'], clock)
144
+ return None
145
+
146
+ freq_data = data['frequency']
147
+
148
+ # Check if it's in grouped format: {'w': [...], 'm': [...]}
149
+ if _is_dict_like(freq_data):
150
+ from .constants import VALID_FREQUENCIES
151
+
152
+ # Check if all keys are valid frequency codes (grouped format)
153
+ keys_are_frequencies = all(
154
+ isinstance(k, str) and k in VALID_FREQUENCIES
155
+ for k in freq_data.keys()
156
+ )
157
+
158
+ # Check if values are lists (grouped format)
159
+ values_are_lists = all(
160
+ isinstance(v, (list, tuple)) for v in freq_data.values()
161
+ )
162
+
163
+ if keys_are_frequencies and values_are_lists:
164
+ # Grouped format: convert to individual format
165
+ result = {}
166
+ for freq, series_list in freq_data.items():
167
+ if not isinstance(series_list, (list, tuple)):
168
+ _raise_config_error(
169
+ f"Frequency '{freq}' must map to a list of series names, got {type(series_list)}"
170
+ )
171
+ for series_name in series_list:
172
+ if not isinstance(series_name, str):
173
+ _raise_config_error(
174
+ f"Series names must be strings, got {type(series_name)} in frequency '{freq}'"
175
+ )
176
+ if series_name in result:
177
+ _raise_config_error(
178
+ f"Series '{series_name}' appears in multiple frequency groups"
179
+ )
180
+ result[series_name] = freq
181
+ return result
182
+ else:
183
+ # Individual format: already in correct format, validate structure
184
+ result = {}
185
+ for series_name, freq in freq_data.items():
186
+ if not isinstance(series_name, str):
187
+ _raise_config_error(
188
+ f"Frequency dict keys must be strings (series names), got {type(series_name)}"
189
+ )
190
+ if not isinstance(freq, str):
191
+ _raise_config_error(
192
+ f"Frequency dict values must be strings (frequency codes), got {type(freq)} for series '{series_name}'"
193
+ )
194
+ result[series_name] = freq
195
+ return result
196
+
141
197
  return None
142
198
 
143
199
 
@@ -23,15 +23,17 @@ DEFAULT_MIN_DELTA = 1e-6 # Minimum change for improvement
23
23
  # ============================================================================
24
24
 
25
25
  # Minimum eigenvalues and variances
26
- MIN_EIGENVALUE = 1e-8 # Minimum eigenvalue for positive definite matrices
26
+ MIN_EIGENVALUE = 1e-6 # Minimum eigenvalue for positive definite matrices (increased from 1e-8 for better conditioning)
27
27
  MIN_DIAGONAL_VARIANCE = 1e-8 # Minimum variance for diagonal elements
28
28
  MIN_OBSERVATION_NOISE = 1e-4 # Minimum observation noise for measurement error (used in EM updates)
29
+ DEFAULT_DDFM_OBSERVATION_NOISE = 1e-15 # Default observation noise for DDFM state-space (matches original TensorFlow)
29
30
  MIN_FACTOR_VARIANCE = 1e-10 # Minimum variance for factors
30
31
  MIN_STD = 1e-8 # Minimum standard deviation
32
+ MIN_STD_FOR_SCALE_CHECK = 1e-10 # Minimum standard deviation for scale ratio computation (more lenient than MIN_STD)
31
33
  DEFAULT_VARIANCE_FALLBACK = 1.0 # Default variance fallback value for numerical stability
32
34
 
33
35
  # Maximum eigenvalues
34
- MAX_EIGENVALUE = 1e6 # Maximum eigenvalue cap
36
+ MAX_EIGENVALUE = 1e3 # Maximum eigenvalue cap (reduced to 1e3 to improve condition number: 1e3/1e-6 = 1e9)
35
37
 
36
38
  # Eigenvalue stability thresholds
37
39
  DEFAULT_EIGENVALUE_MAX_MAGNITUDE = 1.0 # Default maximum eigenvalue magnitude for stability checks
@@ -44,8 +46,11 @@ DEFAULT_CLEAN_INF = MAX_EIGENVALUE # Default value for Inf replacement in clean
44
46
  # Identity matrix defaults
45
47
  DEFAULT_IDENTITY_SCALE = 1.0 # Default scale for create_scaled_identity(n, 1.0)
46
48
  DEFAULT_ZERO_VALUE = 0.0 # Default zero value for explicit zero assignments
47
- DEFAULT_XAVIER_GAIN = 1.0 # Default gain for Xavier initialization
48
- DEFAULT_OUTPUT_LAYER_GAIN = 0.1 # Default gain for output layer Xavier initialization (smaller for stability)
49
+ DEFAULT_INF_VALUE = float('inf') # Default infinity value for loss/scale comparisons
50
+ DEFAULT_XAVIER_GAIN = 1.0 # Default gain for Xavier initialization (matches TensorFlow GlorotNormal)
51
+ DEFAULT_OUTPUT_LAYER_GAIN = 1.0 # Default gain for output layer Xavier initialization (matches original TensorFlow DDFM GlorotNormal for all layers)
52
+ # NOTE: Original TensorFlow DDFM uses GlorotNormal (gain=1.0) for all layers including output layer.
53
+ # Updated to match original TensorFlow behavior to address training divergence (encoder weights too small, near-zero factors).
49
54
 
50
55
  # Companion matrix initialization defaults
51
56
  DEFAULT_INIT_SCALE = 0.01 # Default initialization scale for companion matrix B and C matrices
@@ -59,6 +64,41 @@ DEFAULT_REGULARIZATION = 1e-6 # Default regularization value
59
64
  DEFAULT_CLIP_THRESHOLD = 10.0 # Default clipping threshold (in standard deviations)
60
65
  DEFAULT_DATA_CLIP_THRESHOLD = 100.0 # Default data clipping threshold
61
66
 
67
+ # Scale validation thresholds (for DDFM scale alignment checks)
68
+ DEFAULT_SCALE_RATIO_MAX = 10.0 # Maximum acceptable scale ratio (prediction std / data std)
69
+ DEFAULT_SCALE_RATIO_MIN = 0.1 # Minimum acceptable scale ratio (prediction std / data std)
70
+ DEFAULT_STANDARDIZATION_MEAN_THRESHOLD = 0.1 # Maximum acceptable absolute mean for standardized data (mean should be ≈0)
71
+ DEFAULT_STANDARDIZATION_STD_MIN = 0.1 # Minimum acceptable std for standardized data (std should be ≈1)
72
+ DEFAULT_STANDARDIZATION_STD_MAX = 10.0 # Maximum acceptable std for standardized data (std should be ≈1)
73
+ DEFAULT_STANDARDIZED_TARGET_STD = 1.0 # Target std for standardized data (std should be ≈1.0 for StandardScaler)
74
+
75
+ # Variance collapse diagnostics thresholds (for DDFM variance collapse detection)
76
+ DEFAULT_VARIANCE_COLLAPSE_THRESHOLD = 0.1 # Prediction std threshold for variance collapse detection (std < 0.1 indicates collapse)
77
+ DEFAULT_FACTOR_COLLAPSE_THRESHOLD = 0.01 # Factor magnitude threshold for factor collapse detection (|mean| < 0.01 indicates collapse)
78
+ DEFAULT_BATCHNORM_SUPPRESSION_THRESHOLD = 0.01 # BatchNorm running_var threshold for signal suppression detection (var < 0.01 indicates suppression)
79
+ DEFAULT_TIMESTEP_COLLAPSE_THRESHOLD = 0.1 # Per-time-step std threshold for localized collapse detection (std < 0.1 indicates collapse)
80
+ DEFAULT_TIMESTEP_COLLAPSE_RATIO_THRESHOLD = 0.5 # Ratio threshold for localized collapse (ratio > 0.5 indicates widespread collapse)
81
+ DEFAULT_EXPECTED_FACTOR_MAGNITUDE_MIN = 0.1 # Expected minimum factor magnitude (for warning messages)
82
+ DEFAULT_EXPECTED_FACTOR_MAGNITUDE_MAX = 1.0 # Expected maximum factor magnitude (for warning messages)
83
+
84
+ # DDFM reproduction target values (for debugging and diagnostics)
85
+ DEFAULT_TARGET_PREDICTION_STD = 1.0 # Target prediction std for standardized data (should be ~1.0 for StandardScaler)
86
+ DEFAULT_VARIANCE_COLLAPSE_STD = 0.03 # Observed variance collapse std (std ~0.03 vs target ~1.0)
87
+ DEFAULT_TARGET_CONVERGENCE_ITERATIONS = 10 # Target convergence iterations for exchange_rate dataset (TensorFlow reference)
88
+ DEFAULT_TARGET_DDFM_LOSS = 0.56 # Target DDFM training loss for exchange_rate dataset (TensorFlow reference)
89
+ DEFAULT_DDFM_LOSS_MULTIPLIER = 1.8 # Current loss multiplier vs target (1.00 vs 0.56 = 1.8x)
90
+
91
+ # Logging precision constants
92
+ DEFAULT_SCALE_LOG_PRECISION = 6 # Default precision for scale logging format strings (e.g., .6f)
93
+ DEFAULT_TIME_LOG_PRECISION = 2 # Default precision for time logging format strings (e.g., .2f)
94
+ DEFAULT_LOSS_LOG_PRECISION = 6 # Default precision for loss/delta logging format strings (e.g., .6f)
95
+
96
+ # Time conversion constants
97
+ SECONDS_PER_MINUTE = 60 # Seconds per minute (for time conversion)
98
+
99
+ # Logging level constants
100
+ LOGGING_DEBUG_LEVEL = 10 # logging.DEBUG level for conditional checks
101
+
62
102
  # ============================================================================
63
103
  # Training Defaults
64
104
  # ============================================================================
@@ -68,15 +108,41 @@ DEFAULT_MAX_ITER = 100 # Default maximum EM iterations (general)
68
108
  DEFAULT_EM_MAX_ITER = 5000 # Default maximum EM iterations (DFM-specific)
69
109
  DEFAULT_MAX_EPOCHS = 100 # Default maximum training epochs
70
110
  DEFAULT_MAX_MCMC_ITER = 200 # Default maximum MCMC iterations
111
+ DEFAULT_N_MC_SAMPLES = 10 # Default number of MC samples per MCMC iteration for DDFM denoising training (matches original TensorFlow epochs=10 default, per experiment/config/model/ddfm.yaml)
112
+ DEFAULT_FACTOR_ORDER = 1 # Default factor order for DDFM (AR(1) dynamics)
113
+ DEFAULT_AR_ORDER_2 = 2 # Default AR order 2 for DDFM forecast (AR(2) dynamics)
71
114
 
72
115
  # Batch size defaults
73
116
  DEFAULT_BATCH_SIZE = 32 # Default batch size for neural networks
74
- DEFAULT_DDFM_BATCH_SIZE = 100 # Default batch size for DDFM
117
+ DEFAULT_DDFM_WINDOW_SIZE = 100 # Default window size (time-step batch size) for DDFM
118
+ DEFAULT_DDFM_BATCH_SIZE = 100 # Default batch size for DDFM (matches original TensorFlow batch_size=100)
119
+
120
+ # DDFM target interpolation defaults
121
+ DEFAULT_MIN_TARGET_INTERPOLATE_RATIO = 0.3 # Default minimum target interpolate ratio threshold for DDFM (ratio of missing target values above which interpolation is skipped)
122
+
123
+ # MCMC training defaults (for DDFM sequential MC processing)
124
+ DEFAULT_MCMC_EPOCHS = 1 # Default epochs per MC sample (MCMC training pattern: one epoch per MC sample)
125
+ DEFAULT_MCMC_VERBOSE = 0 # Default verbosity for MCMC training (silent training)
126
+
127
+ # Placeholder defaults (for DDFM placeholder MC dataset)
128
+ DEFAULT_PLACEHOLDER_MC_SAMPLES = 1 # Minimal MC samples for placeholder dataset (replaced after on_train_start)
129
+ DEFAULT_PLACEHOLDER_DATA_SHAPE_T = 100 # Default time steps for placeholder data shape
130
+ DEFAULT_PLACEHOLDER_DATA_SHAPE_N = 10 # Default number of series for placeholder data shape
131
+ DEFAULT_PLACEHOLDER_SEED = 42 # Seed for placeholder random state (common test value, placeholder gets replaced)
132
+ DEFAULT_NUM_WORKERS = 0 # Default number of workers for DataLoader (0 = single-threaded)
133
+ DEFAULT_CUDA_DEVICE_INDEX = 0 # Default CUDA device index for GPU operations (0 = first GPU)
134
+
135
+ # Initialization sample size defaults
136
+ DEFAULT_KDFM_INIT_SAMPLE_SIZE = 100 # Default sample size for KDFM initialization (first N rows used for initialize_from_data)
75
137
 
76
138
  # Learning rate defaults
77
139
  DEFAULT_LEARNING_RATE = 0.001 # Default learning rate
78
140
  DEFAULT_DDFM_LEARNING_RATE = 0.005 # Default learning rate for DDFM
79
141
 
142
+ # Autoencoder training defaults (matches original TensorFlow pattern)
143
+ DEFAULT_AUTOENCODER_FIT_EPOCHS = 1 # Number of epochs per MC sample (matches original TensorFlow: epochs=1 per autoencoder.fit() call)
144
+ DEFAULT_AUTOENCODER_FIT_VERBOSE = 0 # Verbosity level for autoencoder.fit() (0 = silent, matches original TensorFlow verbose=0)
145
+
80
146
  # Gradient clipping
81
147
  DEFAULT_GRAD_CLIP_VAL = 1.0 # Default gradient clipping value
82
148
 
@@ -86,6 +152,22 @@ DEFAULT_WEIGHT_DECAY = 0.0 # Default weight decay (L2 regularization)
86
152
  # Learning rate decay
87
153
  DEFAULT_LR_DECAY_RATE = 0.96 # Default exponential decay rate for learning rate
88
154
 
155
+ # Optimizer defaults
156
+ VALID_OPTIMIZERS = {'Adam', 'AdamW', 'SGD'} # Valid optimizer types for DDFM
157
+
158
+ # Adam optimizer defaults
159
+ DEFAULT_ADAM_BETA1 = 0.9 # Default beta1 (momentum decay) for Adam optimizer
160
+ DEFAULT_ADAM_BETA2 = 0.999 # Default beta2 (squared gradient decay) for Adam optimizer
161
+ DEFAULT_ADAM_EPS = 1e-7 # Default epsilon for Adam optimizer (matches TensorFlow default for DDFM compatibility)
162
+ DEFAULT_PYTORCH_ADAM_EPS = 1e-8 # PyTorch default epsilon for Adam optimizer (for reference)
163
+
164
+ # Batch normalization defaults (matching TensorFlow/Keras defaults)
165
+ DEFAULT_BATCH_NORM_MOMENTUM = 0.99 # TensorFlow/Keras BatchNormalization default momentum
166
+ DEFAULT_BATCH_NORM_EPS = 1e-3 # TensorFlow/Keras BatchNormalization default epsilon
167
+
168
+ # Random seed defaults
169
+ DEFAULT_RANDOM_SEED_MAX = 2**31 # Maximum value for random seed generation (2147483647, 32-bit signed integer max)
170
+
89
171
  # Loss function defaults
90
172
  DEFAULT_HUBER_DELTA = 1.0 # Default delta parameter for Huber loss
91
173
  HUBER_QUADRATIC_COEFF = 0.5 # Quadratic coefficient for Huber loss (0.5 * a^2 term)
@@ -115,7 +197,11 @@ CHOLESKY_LOG_DET_FACTOR = 2.0 # Factor for log determinant computation from Cho
115
197
  # ============================================================================
116
198
 
117
199
  # Encoder layer defaults
118
- DEFAULT_ENCODER_LAYERS = [64, 32] # Default encoder layer sizes
200
+ DEFAULT_ENCODER_LAYERS = [16, 4] # Default encoder layer sizes (matches experiment config and ddfm.py default parameter)
201
+ DEFAULT_NUM_FACTORS = 3 # Default number of factors for DDFM
202
+ DEFAULT_ACTIVATION = 'relu' # Default activation function for DDFM
203
+ DEFAULT_DECODER = 'linear' # Default decoder type for DDFM
204
+ DEFAULT_USE_BATCH_NORM = True # Default batch normalization setting for DDFM
119
205
 
120
206
  # ============================================================================
121
207
  # Data Processing Defaults
@@ -131,8 +217,9 @@ DEFAULT_START_DATE = datetime(2000, 1, 1)
131
217
  # Default window size for DDFM
132
218
  DEFAULT_WINDOW_SIZE = 100
133
219
  DEFAULT_TENT_KERNEL_SIZE = 5 # Default tent kernel size for slower-frequency series aggregation
134
- # Note: DEFAULT_BATCH_SIZE is defined above (line 52) as 32 for general neural networks
135
- # Use DEFAULT_DDFM_BATCH_SIZE (100) for DDFM-specific batch size
220
+ DEFAULT_TENT_KERNEL_REGULARIZATION_MULTIPLIER = 100.0 # Regularization multiplier for tent kernel series (handles ill-conditioning)
221
+ # Note: DEFAULT_BATCH_SIZE is defined above (line 88) as 32 for general neural networks
222
+ # Use DEFAULT_DDFM_WINDOW_SIZE (100) for DDFM-specific window size (time-step batch size)
136
223
 
137
224
  # Warning/display limits
138
225
  MAX_WARNING_ITEMS = 5 # Maximum number of items to show in warning messages
@@ -142,6 +229,9 @@ MAX_ERROR_ITEMS = 20 # Maximum number of items to show in error message details
142
229
  DEFAULT_MIN_OBS = 5 # Default minimum observations for estimation
143
230
  DEFAULT_MIN_OBS_IDIO = 5 # Default minimum observations for idio estimation
144
231
  DEFAULT_MIN_OBS_VAR = 7 # Minimum observations for VAR estimation (order + 5)
232
+ DEFAULT_MIN_OBS_PRETRAIN = 50 # Minimum observations for DDFM pre-training without interpolation
233
+ DEFAULT_MULT_EPOCH_PRETRAIN = 1 # Multiplier for DDFM pre-training epochs
234
+ DEFAULT_PRETRAIN_EPOCHS = 200 # Default number of epochs for DDFM pre-training (matching original paper)
145
235
 
146
236
  # Dimension validation bounds
147
237
  MIN_TIME_STEPS = 1 # Minimum number of time steps (T) required for data
@@ -149,7 +239,9 @@ MIN_VARIABLES = 1 # Minimum number of variables (N) required for data
149
239
  MIN_DDFM_TIME_STEPS = 2 # Minimum number of time steps (T) required for DDFM training (DDFM-specific, different from general MIN_TIME_STEPS=1)
150
240
  MIN_DDFM_DATASET_SIZE_WARNING = 10 # Minimum dataset size (T) below which DDFM denoising training warns about potential instability
151
241
  MIN_ITER_FOR_DELTA_COMPUTATION = 1 # Minimum iteration count required before computing delta (MSE change) in DDFM denoising training
242
+ DEFAULT_MIN_ITER_FOR_CONVERGENCE_CHECK = 2 # Minimum iteration count required before checking convergence in DDFM (check from iteration 3 onwards)
152
243
  MIN_EPS_SHAPE_FOR_IDIO = 1 # Minimum eps shape dimension required for idiosyncratic component processing in DDFM
244
+ MIN_SHAPE_FOR_AR2 = 2 # Minimum shape dimension for AR(2) forecast (need at least 2 previous time steps)
153
245
 
154
246
  # Idiosyncratic component defaults
155
247
  DEFAULT_IDIO_STD = 0.1 # Default idiosyncratic standard deviation (when estimation fails)
@@ -193,7 +285,7 @@ DEFAULT_PROGRESS_LOG_INTERVAL = 5 # Default progress logging interval for EM al
193
285
  # Precision Defaults
194
286
  # ============================================================================
195
287
 
196
- DEFAULT_DTYPE = np.float32 # Default numpy dtype for arrays
288
+ DEFAULT_DTYPE = np.float64 # Default numpy dtype for arrays (float64 for better numerical stability)
197
289
 
198
290
  # PyTorch dtype (matches DEFAULT_DTYPE)
199
291
  try:
@@ -328,6 +420,7 @@ __all__ = [
328
420
  'MIN_OBSERVATION_NOISE',
329
421
  'MIN_FACTOR_VARIANCE',
330
422
  'MIN_STD',
423
+ 'MIN_STD_FOR_SCALE_CHECK',
331
424
  'MAX_EIGENVALUE',
332
425
  'DEFAULT_EIGENVALUE_MAX_MAGNITUDE',
333
426
  'DEFAULT_EIGENVALUE_WARN_THRESHOLD',
@@ -343,19 +436,53 @@ __all__ = [
343
436
  'DEFAULT_REGULARIZATION',
344
437
  'DEFAULT_CLIP_THRESHOLD',
345
438
  'DEFAULT_DATA_CLIP_THRESHOLD',
439
+ 'DEFAULT_SCALE_RATIO_MAX',
440
+ 'DEFAULT_SCALE_RATIO_MIN',
441
+ 'DEFAULT_STANDARDIZATION_MEAN_THRESHOLD',
442
+ 'DEFAULT_STANDARDIZATION_STD_MIN',
443
+ 'DEFAULT_STANDARDIZATION_STD_MAX',
444
+ 'DEFAULT_STANDARDIZED_TARGET_STD',
445
+ 'DEFAULT_TARGET_PREDICTION_STD',
446
+ 'DEFAULT_VARIANCE_COLLAPSE_STD',
447
+ 'DEFAULT_TARGET_CONVERGENCE_ITERATIONS',
448
+ 'DEFAULT_TARGET_DDFM_LOSS',
449
+ 'DEFAULT_DDFM_LOSS_MULTIPLIER',
450
+ 'DEFAULT_SCALE_LOG_PRECISION',
451
+ 'DEFAULT_TIME_LOG_PRECISION',
452
+ 'DEFAULT_LOSS_LOG_PRECISION',
453
+ 'SECONDS_PER_MINUTE',
346
454
  'MIN_CONDITION_NUMBER',
347
455
  'MAX_CONDITION_NUMBER',
348
456
  # Training
349
457
  'DEFAULT_MAX_ITER',
350
458
  'DEFAULT_MAX_EPOCHS',
351
459
  'DEFAULT_MAX_MCMC_ITER',
460
+ 'DEFAULT_N_MC_SAMPLES',
352
461
  'DEFAULT_BATCH_SIZE', # General neural network default (32)
353
- 'DEFAULT_DDFM_BATCH_SIZE', # DDFM-specific default (100)
462
+ 'DEFAULT_DDFM_WINDOW_SIZE', # DDFM-specific window size default (100)
463
+ 'DEFAULT_DDFM_BATCH_SIZE', # DDFM batch size default (100)
464
+ 'DEFAULT_PLACEHOLDER_MC_SAMPLES', # Placeholder MC samples default (1)
465
+ 'DEFAULT_PLACEHOLDER_DATA_SHAPE_T', # Placeholder data shape T default (100)
466
+ 'DEFAULT_PLACEHOLDER_DATA_SHAPE_N', # Placeholder data shape N default (10)
467
+ 'DEFAULT_PLACEHOLDER_SEED', # Placeholder random seed default (42)
468
+ 'DEFAULT_NUM_WORKERS', # DataLoader num_workers default (0)
469
+ 'DEFAULT_CUDA_DEVICE_INDEX', # CUDA device index default (0 = first GPU)
470
+ 'DEFAULT_KDFM_INIT_SAMPLE_SIZE', # KDFM initialization sample size default (100)
354
471
  'DEFAULT_LEARNING_RATE',
355
472
  'DEFAULT_DDFM_LEARNING_RATE',
473
+ 'DEFAULT_AUTOENCODER_FIT_EPOCHS',
474
+ 'DEFAULT_AUTOENCODER_FIT_VERBOSE',
356
475
  'DEFAULT_GRAD_CLIP_VAL',
357
476
  'DEFAULT_WEIGHT_DECAY',
358
477
  'DEFAULT_LR_DECAY_RATE',
478
+ 'VALID_OPTIMIZERS',
479
+ 'DEFAULT_ADAM_BETA1',
480
+ 'DEFAULT_ADAM_BETA2',
481
+ 'DEFAULT_ADAM_EPS',
482
+ 'DEFAULT_TENSORFLOW_ADAM_EPS',
483
+ 'DEFAULT_BATCH_NORM_MOMENTUM',
484
+ 'DEFAULT_BATCH_NORM_EPS',
485
+ 'DEFAULT_RANDOM_SEED_MAX',
359
486
  'DEFAULT_HUBER_DELTA',
360
487
  'HUBER_QUADRATIC_COEFF',
361
488
  'DEFAULT_DDFM_CLIP_RANGE_DEEP',
@@ -368,7 +495,13 @@ __all__ = [
368
495
  'DEFAULT_STRUCTURAL_DIAG_SCALE',
369
496
  'DEFAULT_CHOLESKY_EPS',
370
497
  # Architecture
498
+ 'DEFAULT_FACTOR_ORDER',
499
+ 'DEFAULT_AR_ORDER_2',
371
500
  'DEFAULT_ENCODER_LAYERS',
501
+ 'DEFAULT_NUM_FACTORS',
502
+ 'DEFAULT_ACTIVATION',
503
+ 'DEFAULT_DECODER',
504
+ 'DEFAULT_USE_BATCH_NORM',
372
505
  # Data processing
373
506
  'DEFAULT_NAN_METHOD',
374
507
  'DEFAULT_NAN_K',
@@ -378,12 +511,17 @@ __all__ = [
378
511
  'DEFAULT_MIN_OBS',
379
512
  'DEFAULT_MIN_OBS_IDIO',
380
513
  'DEFAULT_MIN_OBS_VAR',
514
+ 'DEFAULT_MIN_OBS_PRETRAIN',
515
+ 'DEFAULT_MULT_EPOCH_PRETRAIN',
516
+ 'DEFAULT_PRETRAIN_EPOCHS',
381
517
  # Dimension validation
382
518
  'MIN_TIME_STEPS',
383
519
  'MIN_VARIABLES',
520
+ 'MIN_SHAPE_FOR_AR2',
384
521
  'MIN_DDFM_TIME_STEPS',
385
522
  'MIN_DDFM_DATASET_SIZE_WARNING',
386
523
  'MIN_ITER_FOR_DELTA_COMPUTATION',
524
+ 'DEFAULT_MIN_ITER_FOR_CONVERGENCE_CHECK',
387
525
  'MIN_EPS_SHAPE_FOR_IDIO',
388
526
  'DEFAULT_IDIO_STD',
389
527
  'DEFAULT_IDIO_RHO0',
@@ -408,6 +546,7 @@ __all__ = [
408
546
  'DEFAULT_LOG_INTERVAL',
409
547
  'DEFAULT_PROGRESS_LOG_INTERVAL',
410
548
  'DEFAULT_TENT_KERNEL_SIZE',
549
+ 'DEFAULT_TENT_KERNEL_REGULARIZATION_MULTIPLIER',
411
550
  'MAX_ERROR_ITEMS',
412
551
  # IRF
413
552
  'DEFAULT_IRF_HORIZON',
@@ -1,17 +1,19 @@
1
1
  """Configuration schema package for DFM models.
2
2
 
3
3
  This package contains:
4
- - model.py: BaseModelConfig, DFMConfig, DDFMConfig, KDFMConfig - model configurations
5
- - results.py: BaseResult, DFMResult, DDFMResult, KDFMResult - result structures
4
+ - model.py: BaseModelConfig, DFMConfig, DDFMConfig - model configurations
5
+ - results.py: BaseResult, DFMResult, DDFMResult - result structures
6
6
 
7
7
  Note: Series are specified via frequency dict mapping column names to frequencies.
8
8
  """
9
9
 
10
- from .model import BaseModelConfig, DFMConfig, DDFMConfig, KDFMConfig
11
- from .results import BaseResult, DFMResult, DDFMResult, KDFMResult, FitParams
10
+ from .model import BaseModelConfig, DFMConfig, DDFMConfig
11
+ from .results import BaseResult, DFMResult, DDFMResult
12
+ from .params import DFMStateSpaceParams, DDFMStateSpaceParams
12
13
 
13
14
  __all__ = [
14
- 'BaseModelConfig', 'DFMConfig', 'DDFMConfig', 'KDFMConfig',
15
- 'BaseResult', 'DFMResult', 'DDFMResult', 'KDFMResult', 'FitParams',
15
+ 'BaseModelConfig', 'DFMConfig', 'DDFMConfig',
16
+ 'BaseResult', 'DFMResult', 'DDFMResult',
17
+ 'DFMStateSpaceParams', 'DDFMStateSpaceParams',
16
18
  ]
17
19