rustima 0.1.0__tar.gz

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 (143) hide show
  1. rustima-0.1.0/.env.example +16 -0
  2. rustima-0.1.0/.github/workflows/ci.yml +64 -0
  3. rustima-0.1.0/.github/workflows/nightly.yml +83 -0
  4. rustima-0.1.0/.github/workflows/release.yml +242 -0
  5. rustima-0.1.0/.gitignore +22 -0
  6. rustima-0.1.0/BENCHMARK_SPEC.md +219 -0
  7. rustima-0.1.0/Cargo.lock +1212 -0
  8. rustima-0.1.0/Cargo.toml +53 -0
  9. rustima-0.1.0/LICENSE +674 -0
  10. rustima-0.1.0/PKG-INFO +1403 -0
  11. rustima-0.1.0/README.md +1358 -0
  12. rustima-0.1.0/benches/bench_fit.rs +83 -0
  13. rustima-0.1.0/benches/bench_kalman.rs +83 -0
  14. rustima-0.1.0/benchmark_comprehensive.py +152 -0
  15. rustima-0.1.0/benchmark_higher_order.py +178 -0
  16. rustima-0.1.0/build.rs +14 -0
  17. rustima-0.1.0/compare_all_orders.py +240 -0
  18. rustima-0.1.0/debug_loglike.py +672 -0
  19. rustima-0.1.0/debug_mismatch.py +268 -0
  20. rustima-0.1.0/docs/PERF_DIAGNOSIS.md +212 -0
  21. rustima-0.1.0/docs/SUPPORTED_COMBINATIONS.md +102 -0
  22. rustima-0.1.0/docs/api_reference.md +312 -0
  23. rustima-0.1.0/docs/error_codes.md +56 -0
  24. rustima-0.1.0/docs/migration_guide.md +133 -0
  25. rustima-0.1.0/docs/param_compare_2019.md +105 -0
  26. rustima-0.1.0/docs/profiled_kalman_gls_plan.md +312 -0
  27. rustima-0.1.0/docs/statsmodels_compat.md +105 -0
  28. rustima-0.1.0/docs/ver5.2/spec_numerical_hessian.md +257 -0
  29. rustima-0.1.0/docs/ver5.2/spec_opg.md +299 -0
  30. rustima-0.1.0/docs/ver5.2/spec_simple_differencing.md +551 -0
  31. rustima-0.1.0/docs/ver5_convergence_improvement.md +630 -0
  32. rustima-0.1.0/examples/bench_comprehensive.py +328 -0
  33. rustima-0.1.0/examples/bench_vs_statsmodels.py +154 -0
  34. rustima-0.1.0/examples/high_order_bench.rs +100 -0
  35. rustima-0.1.0/examples/sarimax_exog_demo.py +159 -0
  36. rustima-0.1.0/examples/sarimax_hourly_s24.py +193 -0
  37. rustima-0.1.0/fit_summary_report.md +335 -0
  38. rustima-0.1.0/lbfgsb_c/lbfgsb.c +1065 -0
  39. rustima-0.1.0/lbfgsb_c/lbfgsb.h +357 -0
  40. rustima-0.1.0/lbfgsb_c/linesearch.c +765 -0
  41. rustima-0.1.0/lbfgsb_c/linpack.c +297 -0
  42. rustima-0.1.0/lbfgsb_c/miniCBLAS.c +382 -0
  43. rustima-0.1.0/lbfgsb_c/print.c +339 -0
  44. rustima-0.1.0/lbfgsb_c/subalgorithms.c +2228 -0
  45. rustima-0.1.0/lbfgsb_c/timer.c +28 -0
  46. rustima-0.1.0/pyproject.toml +82 -0
  47. rustima-0.1.0/python/rustima/__init__.py +45 -0
  48. rustima-0.1.0/python/rustima/auto.py +789 -0
  49. rustima-0.1.0/python/rustima/model.py +1278 -0
  50. rustima-0.1.0/python_tests/bench_batch_forecast.py +223 -0
  51. rustima-0.1.0/python_tests/bench_comparison.py +201 -0
  52. rustima-0.1.0/python_tests/bench_full_comparison.py +377 -0
  53. rustima-0.1.0/python_tests/bench_grid_5x5.py +433 -0
  54. rustima-0.1.0/python_tests/bench_matrix_6x6_s7_s12_s24.py +206 -0
  55. rustima-0.1.0/python_tests/bench_matrix_parent.py +190 -0
  56. rustima-0.1.0/python_tests/bench_matrix_worker.py +119 -0
  57. rustima-0.1.0/python_tests/bench_memory_speed.py +342 -0
  58. rustima-0.1.0/python_tests/bench_pmdarima_compare.py +165 -0
  59. rustima-0.1.0/python_tests/bench_power_2019_2023.py +220 -0
  60. rustima-0.1.0/python_tests/bench_readme.py +338 -0
  61. rustima-0.1.0/python_tests/bench_report_arima.py +278 -0
  62. rustima-0.1.0/python_tests/bench_report_arimax.py +270 -0
  63. rustima-0.1.0/python_tests/bench_report_sarima.py +317 -0
  64. rustima-0.1.0/python_tests/bench_report_sarimax.py +317 -0
  65. rustima-0.1.0/python_tests/bench_s24_highorder.py +259 -0
  66. rustima-0.1.0/python_tests/bench_sarima_plot.py +156 -0
  67. rustima-0.1.0/python_tests/bench_sarima_retry_pmdarima_1y.py +127 -0
  68. rustima-0.1.0/python_tests/bench_sarima_scaling.py +251 -0
  69. rustima-0.1.0/python_tests/bench_sarima_worker.py +136 -0
  70. rustima-0.1.0/python_tests/bench_v5_report.py +604 -0
  71. rustima-0.1.0/python_tests/benchmark_vs_statsmodels.py +433 -0
  72. rustima-0.1.0/python_tests/build_ppt_pmdarima.py +234 -0
  73. rustima-0.1.0/python_tests/compare_profile_methods_2019.py +136 -0
  74. rustima-0.1.0/python_tests/compare_profile_methods_R.R +54 -0
  75. rustima-0.1.0/python_tests/compare_with_r.R +73 -0
  76. rustima-0.1.0/python_tests/conftest.py +104 -0
  77. rustima-0.1.0/python_tests/diagnose_profile_tr_plateau.py +93 -0
  78. rustima-0.1.0/python_tests/gen_tex_report.py +499 -0
  79. rustima-0.1.0/python_tests/generate_fixtures.py +243 -0
  80. rustima-0.1.0/python_tests/generate_matrix_fixtures.py +362 -0
  81. rustima-0.1.0/python_tests/phase_c_power_auto.py +139 -0
  82. rustima-0.1.0/python_tests/phase_c_robustness.py +150 -0
  83. rustima-0.1.0/python_tests/report_convergence_failures.py +301 -0
  84. rustima-0.1.0/python_tests/run_fit_summary.py +331 -0
  85. rustima-0.1.0/python_tests/show_matrix_coefs.py +78 -0
  86. rustima-0.1.0/python_tests/test_auto.py +229 -0
  87. rustima-0.1.0/python_tests/test_batch.py +132 -0
  88. rustima-0.1.0/python_tests/test_exog.py +323 -0
  89. rustima-0.1.0/python_tests/test_fit.py +205 -0
  90. rustima-0.1.0/python_tests/test_forecast.py +184 -0
  91. rustima-0.1.0/python_tests/test_high_order_accuracy.py +505 -0
  92. rustima-0.1.0/python_tests/test_inference.py +658 -0
  93. rustima-0.1.0/python_tests/test_input_validation.py +714 -0
  94. rustima-0.1.0/python_tests/test_matrix_tier_a.py +441 -0
  95. rustima-0.1.0/python_tests/test_multi_order_accuracy.py +346 -0
  96. rustima-0.1.0/python_tests/test_polars.py +99 -0
  97. rustima-0.1.0/python_tests/test_prediction_quality.py +276 -0
  98. rustima-0.1.0/python_tests/test_profile_trust_region.py +118 -0
  99. rustima-0.1.0/python_tests/test_safety_guards.py +643 -0
  100. rustima-0.1.0/python_tests/test_simple_diff.py +251 -0
  101. rustima-0.1.0/python_tests/test_smoke.py +159 -0
  102. rustima-0.1.0/python_tests/test_trend.py +125 -0
  103. rustima-0.1.0/python_tests/verify_ll_at_same_params.py +91 -0
  104. rustima-0.1.0/python_tests/verify_sarima_vs_sarimax.py +86 -0
  105. rustima-0.1.0/result_v1/00_SUMMARY.md +105 -0
  106. rustima-0.1.0/result_v1/01_ARIMA_comparison.md +51 -0
  107. rustima-0.1.0/result_v1/02_SARIMA_s12_comparison.md +192 -0
  108. rustima-0.1.0/result_v1/02_SARIMA_s24_comparison.md +192 -0
  109. rustima-0.1.0/result_v1/02_SARIMA_s7_comparison.md +192 -0
  110. rustima-0.1.0/result_v1/03_ARIMAX_comparison.md +50 -0
  111. rustima-0.1.0/result_v1/04_SARIMAX_s12_comparison.md +192 -0
  112. rustima-0.1.0/result_v1/04_SARIMAX_s24_comparison.md +192 -0
  113. rustima-0.1.0/result_v1/04_SARIMAX_s7_comparison.md +192 -0
  114. rustima-0.1.0/result_v1/05_auto_arima_benchmark.md +129 -0
  115. rustima-0.1.0/result_v1/bench_all_models.py +397 -0
  116. rustima-0.1.0/result_v1/bench_auto_arima.py +435 -0
  117. rustima-0.1.0/src/batch.rs +393 -0
  118. rustima-0.1.0/src/css.rs +333 -0
  119. rustima-0.1.0/src/error.rs +33 -0
  120. rustima-0.1.0/src/forecast.rs +638 -0
  121. rustima-0.1.0/src/inference.rs +787 -0
  122. rustima-0.1.0/src/initialization.rs +575 -0
  123. rustima-0.1.0/src/kalman.rs +1358 -0
  124. rustima-0.1.0/src/lbfgsb_ffi.rs +75 -0
  125. rustima-0.1.0/src/lbfgsb_wrapper.rs +197 -0
  126. rustima-0.1.0/src/lib.rs +1184 -0
  127. rustima-0.1.0/src/optimizer.rs +4054 -0
  128. rustima-0.1.0/src/params.rs +387 -0
  129. rustima-0.1.0/src/pipeline.rs +173 -0
  130. rustima-0.1.0/src/polynomial.rs +218 -0
  131. rustima-0.1.0/src/score.rs +1451 -0
  132. rustima-0.1.0/src/start_params.rs +1171 -0
  133. rustima-0.1.0/src/state_space.rs +970 -0
  134. rustima-0.1.0/src/test_helpers.rs +110 -0
  135. rustima-0.1.0/src/types.rs +239 -0
  136. rustima-0.1.0/test.ipynb +2108 -0
  137. rustima-0.1.0/tests/fixtures/.gitkeep +0 -0
  138. rustima-0.1.0/tests/fixtures/matrix_tier_a.json +15532 -0
  139. rustima-0.1.0/tests/fixtures/matrix_tier_b.json +47174 -0
  140. rustima-0.1.0/tests/fixtures/statsmodels_fit_reference.json +45 -0
  141. rustima-0.1.0/tests/fixtures/statsmodels_forecast_reference.json +1077 -0
  142. rustima-0.1.0/tests/fixtures/statsmodels_reference.json +2354 -0
  143. rustima-0.1.0/uv.lock +1810 -0
@@ -0,0 +1,16 @@
1
+ # Template for rustima/.env — copy to `.env` and fill in real values.
2
+ # `.env` is gitignored; never commit secrets.
3
+
4
+ # ─── Test PyPI ─────────────────────────────────────────────────────────────
5
+ # Get a token at: https://test.pypi.org/manage/account/token/
6
+ # - Scope: "Entire account" for the first upload (no project exists yet),
7
+ # then re-issue a project-scoped token after the project is created.
8
+ TWINE_USERNAME=__token__
9
+ TWINE_PASSWORD=pypi-AgEN...replace-with-real-token...
10
+ TWINE_REPOSITORY_URL=https://test.pypi.org/legacy/
11
+
12
+ # ─── PyPI (production) ─────────────────────────────────────────────────────
13
+ # Uncomment when ready to publish to real PyPI.
14
+ # Prefer GitHub Trusted Publishing via release.yml over local uploads.
15
+ # PYPI_USERNAME=__token__
16
+ # PYPI_TOKEN=pypi-AgEN...replace-with-real-token...
@@ -0,0 +1,64 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+
9
+ env:
10
+ CARGO_TERM_COLOR: always
11
+
12
+ jobs:
13
+ rust-test:
14
+ name: Rust Tests
15
+ runs-on: ubuntu-latest
16
+ steps:
17
+ - uses: actions/checkout@v4
18
+
19
+ - name: Install Rust toolchain
20
+ uses: dtolnay/rust-action@stable
21
+
22
+ - name: Cache cargo registry
23
+ uses: actions/cache@v4
24
+ with:
25
+ path: |
26
+ ~/.cargo/registry
27
+ ~/.cargo/git
28
+ target
29
+ key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
30
+
31
+ - name: Run Rust tests
32
+ run: cargo test --all-targets
33
+
34
+ python-test:
35
+ name: Python Tests (Tier A + Contract + Smoke)
36
+ runs-on: ubuntu-latest
37
+ needs: rust-test
38
+ steps:
39
+ - uses: actions/checkout@v4
40
+
41
+ - name: Install Rust toolchain
42
+ uses: dtolnay/rust-action@stable
43
+
44
+ - name: Set up Python
45
+ uses: actions/setup-python@v5
46
+ with:
47
+ python-version: "3.12"
48
+
49
+ - name: Install uv
50
+ uses: astral-sh/setup-uv@v4
51
+
52
+ - name: Create venv and install deps
53
+ run: |
54
+ uv venv .venv
55
+ uv pip install numpy pytest statsmodels scipy pandas
56
+
57
+ - name: Build wheel and install
58
+ run: |
59
+ uv pip install maturin
60
+ CARGO_TARGET_DIR=target_wheel uv run maturin build --out /tmp/wheels
61
+ uv pip install --force-reinstall /tmp/wheels/rustima-*.whl
62
+
63
+ - name: Run Python tests (excluding nightly)
64
+ run: .venv/bin/python -m pytest python_tests/ -m "not nightly" -v --tb=short
@@ -0,0 +1,83 @@
1
+ name: Nightly
2
+
3
+ on:
4
+ schedule:
5
+ - cron: "0 3 * * *" # 03:00 UTC daily
6
+ workflow_dispatch: # manual trigger
7
+
8
+ env:
9
+ CARGO_TERM_COLOR: always
10
+
11
+ jobs:
12
+ tier-b-tests:
13
+ name: Tier B Matrix Tests
14
+ runs-on: ubuntu-latest
15
+ steps:
16
+ - uses: actions/checkout@v4
17
+
18
+ - name: Install Rust toolchain
19
+ uses: dtolnay/rust-action@stable
20
+
21
+ - name: Set up Python
22
+ uses: actions/setup-python@v5
23
+ with:
24
+ python-version: "3.12"
25
+
26
+ - name: Install uv
27
+ uses: astral-sh/setup-uv@v4
28
+
29
+ - name: Create venv and install deps
30
+ run: |
31
+ uv venv .venv
32
+ uv pip install numpy pytest statsmodels scipy pandas
33
+
34
+ - name: Build wheel and install
35
+ run: |
36
+ uv pip install maturin
37
+ CARGO_TARGET_DIR=target_wheel uv run maturin build --out /tmp/wheels
38
+ uv pip install --force-reinstall /tmp/wheels/rustima-*.whl
39
+
40
+ - name: Run Tier B nightly tests
41
+ run: .venv/bin/python -m pytest python_tests/test_matrix_tier_b.py -v --tb=short
42
+
43
+ benchmark:
44
+ name: Performance Benchmark
45
+ runs-on: ubuntu-latest
46
+ steps:
47
+ - uses: actions/checkout@v4
48
+
49
+ - name: Install Rust toolchain
50
+ uses: dtolnay/rust-action@stable
51
+
52
+ - name: Set up Python
53
+ uses: actions/setup-python@v5
54
+ with:
55
+ python-version: "3.12"
56
+
57
+ - name: Install uv
58
+ uses: astral-sh/setup-uv@v4
59
+
60
+ - name: Create venv and install deps
61
+ run: |
62
+ uv venv .venv
63
+ uv pip install numpy pytest statsmodels scipy pandas
64
+
65
+ - name: Build wheel (release) and install
66
+ run: |
67
+ uv pip install maturin
68
+ CARGO_TARGET_DIR=target_wheel uv run maturin build --release --out /tmp/wheels
69
+ uv pip install --force-reinstall /tmp/wheels/rustima-*.whl
70
+
71
+ - name: Run Rust benchmarks
72
+ run: cargo bench --bench bench_fit -- --output-format bencher | tee bench_results.txt
73
+
74
+ - name: Run Python benchmark comparison
75
+ run: .venv/bin/python python_tests/bench_comparison.py | tee python_bench_results.txt
76
+
77
+ - name: Upload benchmark results
78
+ uses: actions/upload-artifact@v4
79
+ with:
80
+ name: benchmark-results
81
+ path: |
82
+ bench_results.txt
83
+ python_bench_results.txt
@@ -0,0 +1,242 @@
1
+ name: Release
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - "v*"
7
+ workflow_dispatch:
8
+ inputs:
9
+ publish_to_pypi:
10
+ description: "Publish to PyPI (real, not test.pypi)"
11
+ type: boolean
12
+ default: false
13
+
14
+ permissions:
15
+ contents: write
16
+
17
+ env:
18
+ CARGO_TERM_COLOR: always
19
+
20
+ jobs:
21
+ # ----------------------------------------------------------------------------
22
+ # Linux: manylinux2014 (glibc 2.17+) — required for PyPI acceptance
23
+ # ----------------------------------------------------------------------------
24
+ build-linux:
25
+ name: Linux ${{ matrix.target }} (py${{ matrix.python }})
26
+ runs-on: ubuntu-latest
27
+ strategy:
28
+ fail-fast: false
29
+ matrix:
30
+ target: [x86_64]
31
+ python: ["3.10", "3.11", "3.12", "3.13"]
32
+ steps:
33
+ - uses: actions/checkout@v4
34
+
35
+ - name: Set up Python ${{ matrix.python }}
36
+ uses: actions/setup-python@v5
37
+ with:
38
+ python-version: ${{ matrix.python }}
39
+
40
+ - name: Build wheel (manylinux2014)
41
+ uses: PyO3/maturin-action@v1
42
+ with:
43
+ target: ${{ matrix.target }}
44
+ args: --release --out dist --interpreter ${{ matrix.python }}
45
+ manylinux: "2014"
46
+ working-directory: .
47
+
48
+ - name: Install wheel & smoke-test
49
+ run: |
50
+ python -m pip install --upgrade pip
51
+ python -m pip install numpy polars pytest
52
+ python -m pip install --force-reinstall --no-index --find-links dist/ rustima
53
+ python -m pytest python_tests/test_smoke.py -v --tb=short
54
+
55
+ - name: Upload wheel
56
+ uses: actions/upload-artifact@v4
57
+ with:
58
+ name: wheel-linux-${{ matrix.target }}-py${{ matrix.python }}
59
+ path: dist/*.whl
60
+
61
+ # ----------------------------------------------------------------------------
62
+ # macOS: arm64 (Apple Silicon) + x86_64 (Intel)
63
+ # ----------------------------------------------------------------------------
64
+ build-macos:
65
+ name: macOS ${{ matrix.target }} (py${{ matrix.python }})
66
+ runs-on: ${{ matrix.runner }}
67
+ strategy:
68
+ fail-fast: false
69
+ matrix:
70
+ include:
71
+ - runner: macos-latest
72
+ target: aarch64-apple-darwin
73
+ - runner: macos-13
74
+ target: x86_64-apple-darwin
75
+ python: ["3.10", "3.11", "3.12", "3.13"]
76
+ steps:
77
+ - uses: actions/checkout@v4
78
+
79
+ - name: Set up Python ${{ matrix.python }}
80
+ uses: actions/setup-python@v5
81
+ with:
82
+ python-version: ${{ matrix.python }}
83
+
84
+ - name: Build wheel
85
+ uses: PyO3/maturin-action@v1
86
+ with:
87
+ target: ${{ matrix.target }}
88
+ args: --release --out dist --interpreter ${{ matrix.python }}
89
+ working-directory: .
90
+
91
+ - name: Install wheel & smoke-test
92
+ run: |
93
+ python -m pip install --upgrade pip
94
+ python -m pip install numpy polars pytest
95
+ python -m pip install --force-reinstall --no-index --find-links dist/ rustima
96
+ python -m pytest python_tests/test_smoke.py -v --tb=short
97
+
98
+ - name: Upload wheel
99
+ uses: actions/upload-artifact@v4
100
+ with:
101
+ name: wheel-macos-${{ matrix.target }}-py${{ matrix.python }}
102
+ path: dist/*.whl
103
+
104
+ # ----------------------------------------------------------------------------
105
+ # Windows: x86_64
106
+ # ----------------------------------------------------------------------------
107
+ build-windows:
108
+ name: Windows ${{ matrix.target }} (py${{ matrix.python }})
109
+ runs-on: windows-latest
110
+ strategy:
111
+ fail-fast: false
112
+ matrix:
113
+ target: [x64]
114
+ python: ["3.10", "3.11", "3.12", "3.13"]
115
+ steps:
116
+ - uses: actions/checkout@v4
117
+
118
+ - name: Set up Python ${{ matrix.python }}
119
+ uses: actions/setup-python@v5
120
+ with:
121
+ python-version: ${{ matrix.python }}
122
+ architecture: ${{ matrix.target }}
123
+
124
+ - name: Build wheel
125
+ uses: PyO3/maturin-action@v1
126
+ with:
127
+ target: ${{ matrix.target }}
128
+ args: --release --out dist --interpreter ${{ matrix.python }}
129
+ working-directory: .
130
+
131
+ - name: Install wheel & smoke-test
132
+ shell: bash
133
+ run: |
134
+ python -m pip install --upgrade pip
135
+ python -m pip install numpy polars pytest
136
+ python -m pip install --force-reinstall --no-index --find-links dist/ rustima
137
+ python -m pytest python_tests/test_smoke.py -v --tb=short
138
+
139
+ - name: Upload wheel
140
+ uses: actions/upload-artifact@v4
141
+ with:
142
+ name: wheel-windows-${{ matrix.target }}-py${{ matrix.python }}
143
+ path: dist/*.whl
144
+
145
+ # ----------------------------------------------------------------------------
146
+ # sdist (source distribution) — required so non-wheel platforms can build
147
+ # ----------------------------------------------------------------------------
148
+ build-sdist:
149
+ name: Build sdist
150
+ runs-on: ubuntu-latest
151
+ steps:
152
+ - uses: actions/checkout@v4
153
+
154
+ - name: Build sdist
155
+ uses: PyO3/maturin-action@v1
156
+ with:
157
+ command: sdist
158
+ args: --out dist
159
+ working-directory: .
160
+
161
+ - name: Upload sdist
162
+ uses: actions/upload-artifact@v4
163
+ with:
164
+ name: sdist
165
+ path: dist/*.tar.gz
166
+
167
+ # ----------------------------------------------------------------------------
168
+ # GitHub Release with all wheels + sdist
169
+ # ----------------------------------------------------------------------------
170
+ create-release:
171
+ name: Create GitHub Release
172
+ needs: [build-linux, build-macos, build-windows, build-sdist]
173
+ if: startsWith(github.ref, 'refs/tags/v')
174
+ runs-on: ubuntu-latest
175
+ steps:
176
+ - uses: actions/checkout@v4
177
+
178
+ - name: Download all artifacts
179
+ uses: actions/download-artifact@v4
180
+ with:
181
+ path: dist/
182
+ pattern: "wheel-*"
183
+ merge-multiple: true
184
+
185
+ - name: Download sdist
186
+ uses: actions/download-artifact@v4
187
+ with:
188
+ name: sdist
189
+ path: dist/
190
+
191
+ - name: Create Release
192
+ uses: softprops/action-gh-release@v2
193
+ with:
194
+ files: |
195
+ dist/*.whl
196
+ dist/*.tar.gz
197
+ generate_release_notes: true
198
+
199
+ # ----------------------------------------------------------------------------
200
+ # PyPI publish via Trusted Publishing (OIDC, no API token required)
201
+ #
202
+ # Setup (one-time): on pypi.org → project settings → "Publishing" →
203
+ # "Add a new pending publisher" with:
204
+ # owner = zongseung
205
+ # repo = Rust-python-arima
206
+ # workflow = release.yml
207
+ # environment = pypi
208
+ # Then create a GitHub environment named "pypi" with required reviewers
209
+ # if you want manual approval before publish.
210
+ # ----------------------------------------------------------------------------
211
+ publish-pypi:
212
+ name: Publish to PyPI
213
+ needs: [build-linux, build-macos, build-windows, build-sdist]
214
+ if: startsWith(github.ref, 'refs/tags/v') || (github.event_name == 'workflow_dispatch' && inputs.publish_to_pypi)
215
+ runs-on: ubuntu-latest
216
+ environment:
217
+ name: pypi
218
+ url: https://pypi.org/p/rustima
219
+ permissions:
220
+ id-token: write
221
+ steps:
222
+ - name: Download all wheel artifacts
223
+ uses: actions/download-artifact@v4
224
+ with:
225
+ path: dist/
226
+ pattern: "wheel-*"
227
+ merge-multiple: true
228
+
229
+ - name: Download sdist
230
+ uses: actions/download-artifact@v4
231
+ with:
232
+ name: sdist
233
+ path: dist/
234
+
235
+ - name: List artifacts
236
+ run: ls -lh dist/
237
+
238
+ - name: Publish to PyPI
239
+ uses: pypa/gh-action-pypi-publish@release/v1
240
+ with:
241
+ packages-dir: dist/
242
+ skip-existing: true
@@ -0,0 +1,22 @@
1
+ *.cache
2
+ *.claude
3
+ planner
4
+ __pycache__
5
+ .venv
6
+ /planner
7
+ /target_wheel
8
+ **/target_wheel/
9
+ Rust-python-arima/sarimax_rs/target/
10
+ CLAUDE.md
11
+ # 컴파일된 확장 모듈 (빌드 아티팩트) — .py 소스는 트래킹 유지
12
+ python/rustima/*.so
13
+ python/rustima/__pycache__/
14
+
15
+ # Secrets / credentials (PyPI tokens, etc.) — NEVER commit
16
+ .env
17
+ .env.*
18
+ !.env.example
19
+ !.env.template
20
+
21
+ # Build distribution
22
+ /dist/
@@ -0,0 +1,219 @@
1
+ # sarimax-rs 성능 및 정확도 검증 기획서
2
+
3
+ ## 1. 목적
4
+
5
+ sarimax-rs (Rust 엔진)가 Python statsmodels SARIMAX 대비 **모든 모델 유형에서** 속도 우위를 달성하고, 수치 정확도가 허용 범위 내에 있음을 체계적으로 검증한다.
6
+
7
+ ## 2. 검증 대상 모델
8
+
9
+ | # | 모델 | order | seasonal_order | 데이터 길이 | 복잡도 |
10
+ |---|------|-------|----------------|------------|--------|
11
+ | 1 | AR(1) | (1,0,0) | (0,0,0,0) | 200 | Low |
12
+ | 2 | AR(2) | (2,0,0) | (0,0,0,0) | 300 | Low |
13
+ | 3 | MA(1) | (0,0,1) | (0,0,0,0) | 200 | Low |
14
+ | 4 | ARMA(1,1) | (1,0,1) | (0,0,0,0) | 300 | Medium |
15
+ | 5 | ARMA(2,2) | (2,0,2) | (0,0,0,0) | 400 | Medium |
16
+ | 6 | ARIMA(1,1,1) | (1,1,1) | (0,0,0,0) | 300 | Medium |
17
+ | 7 | ARIMA(2,1,2) | (2,1,2) | (0,0,0,0) | 400 | High |
18
+ | 8 | SARIMA(1,0,0)(1,0,0,4) | (1,0,0) | (1,0,0,4) | 200 | Medium |
19
+ | 9 | SARIMA(1,1,1)(1,1,1,12) | (1,1,1) | (1,1,1,12) | 300 | High |
20
+ | 10 | SARIMA(2,1,1)(1,1,1,12) | (2,1,1) | (1,1,1,12) | 500 | Very High |
21
+
22
+ ## 3. 벤치마크 측정 항목
23
+
24
+ ### 3.1 속도 (Performance)
25
+
26
+ | 측정 항목 | 방법 | 기대 결과 |
27
+ |-----------|------|-----------|
28
+ | Single fit 시간 | best-of-3, wall clock (ms) | Rust > 1.0x speedup (모든 모델) |
29
+ | Kalman loglike 시간 | best-of-5, wall clock (ms) | Rust > 2.0x speedup |
30
+ | Batch fit (50 series) | best-of-2, wall clock (ms) | Rust > 5.0x speedup (Rayon 병렬) |
31
+ | Forecast (10-step) | best-of-5, wall clock (ms) | Rust > 2.0x speedup |
32
+
33
+ ### 3.2 정확도 (Accuracy)
34
+
35
+ | 측정 항목 | 허용 범위 | 비교 대상 |
36
+ |-----------|-----------|-----------|
37
+ | Log-likelihood (oracle params) | \|err\| < 1e-6 | statsmodels loglike |
38
+ | Fitted params | max \|err\| < 1e-2 | statsmodels fit params |
39
+ | Fitted loglike | \|err\| < 3.0 | statsmodels fit loglike |
40
+ | AIC / BIC | \|err\| < 6.0 | statsmodels AIC/BIC |
41
+ | Forecast mean (10-step) | max \|err\| < 1e-4 | statsmodels forecast |
42
+ | Forecast CI | max \|err\| < 1e-3 | statsmodels CI |
43
+
44
+ ### 3.3 수렴성 (Convergence)
45
+
46
+ | 측정 항목 | 기대 결과 |
47
+ |-----------|-----------|
48
+ | 수렴률 (converged=true) | >= 90% (모든 모델) |
49
+ | 반복 횟수 비교 | Rust <= statsmodels * 1.5 |
50
+
51
+ ## 4. 테스트 실행 절차
52
+
53
+ ```bash
54
+ # 1. 빌드
55
+ cd sarimax_rs && maturin develop --release
56
+
57
+ # 2. 종합 벤치마크 실행
58
+ .venv/bin/python python_tests/bench_full_comparison.py
59
+
60
+ # 3. Rust 내부 벤치마크
61
+ cargo bench
62
+ ```
63
+
64
+ ## 5. 결과 판정 기준
65
+
66
+ ### PASS 조건 (모든 항목 충족 필요)
67
+
68
+ - [x] **속도**: 10개 모델 전부 Rust >= 1.0x speedup (10/10 PASS)
69
+ - [x] **정확도**: oracle loglike 오차 < 1e-6 (10/10 모델 PASS)
70
+ - [ ] **정확도**: fitted params 오차 < 1e-2 (8/10 모델, ARIMA(2,1,2) + ARIMA(1,1,1) 실패)
71
+ - [ ] **정확도**: forecast mean 오차 < 1e-4 (1/10 모델)
72
+ - [x] **수렴**: 수렴률 >= 90% (10/10 모델 PASS)
73
+ - [x] **배치**: 50-series batch speedup >= 3.0x (66.2x, PASS)
74
+
75
+ ---
76
+
77
+ ## 6. 벤치마크 결과 이력
78
+
79
+ ### 6.1 초기 결과 (2026-02-22, 옵티마이저 개선 전)
80
+
81
+ #### 환경
82
+ - Platform: macOS-15.1-arm64 (Apple Silicon)
83
+ - Python: 3.14.3
84
+ - sarimax_rs: 0.1.0
85
+ - Config: method=lbfgsb (multi-start), maxiter=200
86
+
87
+ #### 속도
88
+
89
+ | 모델 | Rust (ms) | SM (ms) | Speedup | RS iter | SM iter |
90
+ |------|-----------|---------|---------|---------|---------|
91
+ | AR(1) n=200 | 0.3 | 2.0 | 6.6x | 21 | 3 |
92
+ | AR(2) n=300 | 3.7 | 3.2 | 0.9x | 45 | 3 |
93
+ | MA(1) n=200 | 0.5 | 2.3 | 4.8x | 30 | 4 |
94
+ | ARMA(1,1) n=300 | 3.8 | 4.3 | 1.1x | 50 | 5 |
95
+ | ARMA(2,2) n=400 | 32.2 | 13.6 | 0.4x | 67 | 11 |
96
+ | ARIMA(1,1,1) n=300 | 8.5 | 7.1 | 0.8x | 43 | 11 |
97
+ | ARIMA(2,1,2) n=400 | 67.2 | 66.3 | 1.0x | 87 | 36 |
98
+ | SARIMA(1,0,0)(1,0,0,4) | 22.3 | 5.2 | 0.2x | 45 | 7 |
99
+ | SARIMA(1,1,1)(1,1,1,12) | 2136.5 | 223.0 | 0.1x | 97 | 21 |
100
+ | SARIMA(2,1,1)(1,1,1,12) | 1155.6 | 739.5 | 0.6x | 140 | 34 |
101
+
102
+ **판정**: **FAIL** — 3/10 모델만 확실히 빠름
103
+
104
+ #### 근본 원인
105
+ - Multi-start 전략이 5~15개의 optimization run 수행 (불필요한 반복)
106
+ - L-BFGS-B 파라미터가 scipy 기본값과 상이 (m=7, pgtol=1e-7)
107
+ - AR/MA 파라미터에 불필요한 bounds [-20, 20] 적용 (L-BFGS-B Cauchy point 비효율)
108
+
109
+ ---
110
+
111
+ ### 6.2 최종 결과 (2026-02-22, 옵티마이저 개선 후)
112
+
113
+ #### 환경
114
+ - Platform: macOS-15.1-arm64 (Apple Silicon)
115
+ - Python: 3.14.3
116
+ - sarimax_rs: 0.1.0
117
+ - Config: method=lbfgsb (single-run), maxiter=200
118
+
119
+ #### 적용된 개선사항
120
+ 1. **Multi-start 제거**: 기본 `"lbfgsb"` 메서드를 단일 L-BFGS-B 실행으로 변경 (multi-start는 `"lbfgsb-multi"`로 분리)
121
+ 2. **L-BFGS-B 파라미터 정렬**: scipy 기본값과 동일하게 조정 (m=10, factr=1e7, pgtol=1e-5)
122
+ 3. **Fused function+gradient**: StateSpace 재생성 없이 분석적 그래디언트와 함수값을 동시 계산
123
+ 4. **Unbounded 파라미터**: enforce_stationarity/invertibility=true일 때 AR/MA bounds 제거 (Monahan/Jones 변환이 제약을 처리하므로 L-BFGS-B bounds 불필요)
124
+
125
+ #### 속도
126
+
127
+ | 모델 | Rust (ms) | SM (ms) | Speedup | RS iter | SM iter |
128
+ |------|-----------|---------|---------|---------|---------|
129
+ | AR(1) n=200 | **0.4** | 3.1 | **8.5x** | 21 | 3 |
130
+ | AR(2) n=300 | **1.2** | 5.0 | **4.0x** | 17 | 3 |
131
+ | MA(1) n=200 | **0.4** | 3.6 | **8.2x** | 16 | 4 |
132
+ | ARMA(1,1) n=300 | **0.7** | 6.4 | **9.1x** | 10 | 5 |
133
+ | ARMA(2,2) n=400 | **10.6** | 20.4 | **1.9x** | 40 | 11 |
134
+ | ARIMA(1,1,1) n=300 | **3.0** | 10.6 | **3.6x** | 23 | 11 |
135
+ | ARIMA(2,1,2) n=400 | **12.5** | 101.3 | **8.1x** | 27 | 36 |
136
+ | SARIMA(1,0,0)(1,0,0,4) | **6.7** | 8.1 | **1.2x** | 25 | 7 |
137
+ | SARIMA(1,1,1)(1,1,1,12) | **206.6** | 337.0 | **1.6x** | 20 | 21 |
138
+ | SARIMA(2,1,1)(1,1,1,12) | **1085.2** | 1131.8 | **1.0x** | 49 | 34 |
139
+
140
+ **판정**: **PASS** — 10/10 모델 전부 Rust >= 1.0x speedup
141
+
142
+ #### 정확도
143
+
144
+ | 모델 | Oracle LL | Param err | LL err | FC mean | FC CI |
145
+ |------|-----------|-----------|--------|---------|-------|
146
+ | AR(1) | 5.7e-14 | 6.9e-05 | 9.1e-07 | 2.8e-05 | 6.2e-03 |
147
+ | AR(2) | 1.1e-13 | 1.6e-03 | 5.9e-04 | 5.6e-04 | 1.0e-02 |
148
+ | MA(1) | 2.6e-10 | 3.8e-03 | 1.5e-03 | 3.5e-03 | 1.4e-02 |
149
+ | ARMA(1,1) | 1.3e-10 | 1.3e-03 | 9.2e-04 | 2.1e-03 | 1.3e-02 |
150
+ | ARMA(2,2) | 1.8e-10 | 2.7e-03 | 3.4e-04 | 1.6e-03 | 4.5e-03 |
151
+ | ARIMA(1,1,1) | 5.0e-11 | 2.7e-02 | 1.1e-03 | 6.5e-03 | 1.3e-02 |
152
+ | **ARIMA(2,1,2)** | 4.0e-08 | **1.5e+00** | **4.4e-01** | 1.5e-01 | 6.3e-01 |
153
+ | SARIMA(1,0,0)(1,0,0,4) | 5.7e-14 | 2.9e-03 | 1.4e-03 | 4.0e-03 | 3.2e-02 |
154
+ | SARIMA(1,1,1)(1,1,1,12) | 2.6e-10 | 3.5e-03 | 1.1e-03 | 3.3e-02 | 7.1e-02 |
155
+ | SARIMA(2,1,1)(1,1,1,12) | 1.2e-09 | 1.8e-03 | 6.8e-04 | 2.3e-02 | 5.4e-02 |
156
+
157
+ #### 배치
158
+
159
+ | 시나리오 | Rust (ms) | SM (ms) | Speedup | 수렴 |
160
+ |----------|-----------|---------|---------|------|
161
+ | AR(1) 50x n=200 | **2.4** | 155.6 | **66.2x** | 50/50 |
162
+
163
+ #### 종합 판정
164
+
165
+ | 항목 | 결과 | 상세 |
166
+ |------|------|------|
167
+ | 속도 (전 모델 우위) | **PASS** | 10/10 (1.0x ~ 9.1x) |
168
+ | Oracle loglike < 1e-6 | **PASS** | 10/10 |
169
+ | Param error < 1e-2 | **FAIL** | 8/10 (ARIMA(2,1,2), ARIMA(1,1,1) 실패) |
170
+ | Forecast mean < 1e-4 | **FAIL** | 1/10 |
171
+ | 수렴률 >= 90% | **PASS** | 10/10 |
172
+ | Batch speedup >= 3x | **PASS** | 66.2x |
173
+
174
+ ---
175
+
176
+ ## 7. 잔존 이슈 분석
177
+
178
+ ### 7.1 ARIMA(2,1,2) 파라미터 수렴 문제
179
+ - param error 1.5 → statsmodels와 다른 국소 최적점에 수렴
180
+ - oracle loglike는 4.0e-08으로 정확 → Kalman filter 자체는 정상
181
+ - 다차원 MA가 포함된 모델에서 likelihood surface의 다중 최적점 문제
182
+
183
+ ### 7.2 ARIMA(1,1,1) 파라미터 오차 (경미)
184
+ - param error 2.7e-02 → 허용 범위(1e-2) 초과이나 borderline
185
+ - LL error 1.1e-03으로 작음 → 유사한 loglike를 가진 근접 파라미터에 수렴
186
+
187
+ ### 7.3 Forecast 오차
188
+ - forecast mean 오차는 대부분 fitted params 차이에서 기인
189
+ - oracle loglike가 1e-14 수준이므로 Kalman filter/forecast 로직 자체는 정확
190
+ - 향후 param 정확도 향상 시 자동 개선 예상
191
+
192
+ ---
193
+
194
+ ## 8. 개선 로드맵
195
+
196
+ ### Phase 1: 옵티마이저 효율 개선 — ✅ 완료
197
+ - [x] Multi-start 전략 제거 → 단일 L-BFGS-B 실행
198
+ - [x] L-BFGS-B 파라미터 scipy 기본값 정렬 (m=10, factr=1e7, pgtol=1e-5)
199
+ - [x] Fused function+gradient (분석적 그래디언트 + StateSpace 재사용)
200
+ - [x] Unbounded 파라미터 (enforce시 bounds 제거)
201
+
202
+ ### Phase 2: 단일 모델 속도 검증 — ✅ 완료
203
+ - [x] 옵티마이저 개선 후 재벤치마크
204
+ - [x] 목표 달성: 모든 모델에서 speedup >= 1.0x
205
+
206
+ ### Phase 3: Forecast 정확도 향상 (향후)
207
+ - [ ] ARIMA(2,1,2) 다중 국소 최적점 탐색 전략
208
+ - [ ] ARIMA(1,1,1) param error 경감 (2.7e-02 → 1e-02 이하)
209
+ - [ ] Forecast는 param이 동일하면 정확함 (oracle loglike PASS로 검증됨)
210
+
211
+ ## 9. 데이터 생성 방식
212
+
213
+ 모든 벤치마크 데이터는 `np.random.seed(42)` 기반 결정적(deterministic) 생성:
214
+
215
+ - AR 데이터: `y[t] = phi * y[t-1] + noise`
216
+ - ARIMA 데이터: `cumsum(noise)` + AR/MA 구조
217
+ - SARIMA 데이터: `y[t] = phi * y[t-1] + Phi * y[t-s] + noise`
218
+
219
+ 이를 통해 재현 가능한 벤치마크 결과를 보장한다.