bsts-causalimpact 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 (54) hide show
  1. bsts_causalimpact-0.1.0/.cargo/config.toml +8 -0
  2. bsts_causalimpact-0.1.0/.claude/settings.json +6 -0
  3. bsts_causalimpact-0.1.0/.githooks/pre-commit +10 -0
  4. bsts_causalimpact-0.1.0/.githooks/pre-push +12 -0
  5. bsts_causalimpact-0.1.0/.githooks/prepare-commit-msg +44 -0
  6. bsts_causalimpact-0.1.0/.github/workflows/ci.yml +45 -0
  7. bsts_causalimpact-0.1.0/.github/workflows/numerical-equivalence.yml +83 -0
  8. bsts_causalimpact-0.1.0/.github/workflows/release.yml +70 -0
  9. bsts_causalimpact-0.1.0/.gitignore +13 -0
  10. bsts_causalimpact-0.1.0/.python-version +1 -0
  11. bsts_causalimpact-0.1.0/CODE_OF_CONDUCT.md +65 -0
  12. bsts_causalimpact-0.1.0/CONTRIBUTING.md +81 -0
  13. bsts_causalimpact-0.1.0/Cargo.lock +416 -0
  14. bsts_causalimpact-0.1.0/Cargo.toml +16 -0
  15. bsts_causalimpact-0.1.0/LICENSE +21 -0
  16. bsts_causalimpact-0.1.0/PKG-INFO +13 -0
  17. bsts_causalimpact-0.1.0/README.md +217 -0
  18. bsts_causalimpact-0.1.0/SECURITY.md +32 -0
  19. bsts_causalimpact-0.1.0/benchmarks/benchmark.py +181 -0
  20. bsts_causalimpact-0.1.0/benchmarks/results.md +11 -0
  21. bsts_causalimpact-0.1.0/docs/compatibility-matrix.md +76 -0
  22. bsts_causalimpact-0.1.0/docs/migration-from-r.md +94 -0
  23. bsts_causalimpact-0.1.0/docs/migration-from-tfp.md +102 -0
  24. bsts_causalimpact-0.1.0/docs/quickstart.ipynb +199 -0
  25. bsts_causalimpact-0.1.0/pyproject.toml +36 -0
  26. bsts_causalimpact-0.1.0/python/causal_impact/__init__.py +7 -0
  27. bsts_causalimpact-0.1.0/python/causal_impact/analysis.py +117 -0
  28. bsts_causalimpact-0.1.0/python/causal_impact/data.py +215 -0
  29. bsts_causalimpact-0.1.0/python/causal_impact/main.py +167 -0
  30. bsts_causalimpact-0.1.0/python/causal_impact/options.py +42 -0
  31. bsts_causalimpact-0.1.0/python/causal_impact/plot.py +97 -0
  32. bsts_causalimpact-0.1.0/python/causal_impact/summary.py +88 -0
  33. bsts_causalimpact-0.1.0/rust-toolchain.toml +2 -0
  34. bsts_causalimpact-0.1.0/scripts/generate_r_reference.R +127 -0
  35. bsts_causalimpact-0.1.0/src/distributions.rs +106 -0
  36. bsts_causalimpact-0.1.0/src/kalman.rs +173 -0
  37. bsts_causalimpact-0.1.0/src/lib.rs +83 -0
  38. bsts_causalimpact-0.1.0/src/sampler.rs +705 -0
  39. bsts_causalimpact-0.1.0/src/state_space.rs +46 -0
  40. bsts_causalimpact-0.1.0/tests/__init__.py +0 -0
  41. bsts_causalimpact-0.1.0/tests/conftest.py +50 -0
  42. bsts_causalimpact-0.1.0/tests/fixtures/r_reference_basic.json +21 -0
  43. bsts_causalimpact-0.1.0/tests/fixtures/r_reference_covariates.json +24 -0
  44. bsts_causalimpact-0.1.0/tests/fixtures/r_reference_no_effect.json +21 -0
  45. bsts_causalimpact-0.1.0/tests/fixtures/r_reference_strong_effect.json +21 -0
  46. bsts_causalimpact-0.1.0/tests/test_analysis.py +405 -0
  47. bsts_causalimpact-0.1.0/tests/test_data.py +181 -0
  48. bsts_causalimpact-0.1.0/tests/test_integration.py +148 -0
  49. bsts_causalimpact-0.1.0/tests/test_numerical_equivalence.py +340 -0
  50. bsts_causalimpact-0.1.0/tests/test_options.py +249 -0
  51. bsts_causalimpact-0.1.0/tests/test_plot.py +88 -0
  52. bsts_causalimpact-0.1.0/tests/test_rust_sampler.py +303 -0
  53. bsts_causalimpact-0.1.0/tests/test_spike_slab.py +478 -0
  54. bsts_causalimpact-0.1.0/tests/test_summary.py +77 -0
@@ -0,0 +1,8 @@
1
+ [target.x86_64-apple-darwin]
2
+ rustflags = ["-C", "target-cpu=native"]
3
+
4
+ [target.aarch64-apple-darwin]
5
+ rustflags = ["-C", "target-cpu=native"]
6
+
7
+ [target.x86_64-unknown-linux-gnu]
8
+ rustflags = ["-C", "target-cpu=native"]
@@ -0,0 +1,6 @@
1
+ {
2
+ "attribution": {
3
+ "commit": "",
4
+ "pr": ""
5
+ }
6
+ }
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ if command -v ruff &>/dev/null; then
5
+ ruff check .
6
+ elif [ -f .venv/bin/ruff ]; then
7
+ .venv/bin/ruff check .
8
+ else
9
+ echo "pre-commit: ruff not found, skipping (CI will catch)"
10
+ fi
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ echo "=== pre-push: cargo test ==="
5
+ cargo test
6
+
7
+ echo "=== pre-push: pytest ==="
8
+ if [ -f .venv/bin/pytest ]; then
9
+ .venv/bin/pytest tests/ --tb=short -q
10
+ else
11
+ echo "pre-push: pytest not found, skipping (CI will catch)"
12
+ fi
@@ -0,0 +1,44 @@
1
+ #!/usr/bin/env bash
2
+ # Claude Code の attribution / Co-Authored-By trailer をコミット前に削除する safety net
3
+ # 有効化: git config core.hooksPath .githooks
4
+
5
+ set -euo pipefail
6
+
7
+ MSG_FILE="${1:-}"
8
+ if [ -z "$MSG_FILE" ] || [ ! -f "$MSG_FILE" ]; then
9
+ exit 0
10
+ fi
11
+
12
+ python3 - "$MSG_FILE" <<'PY'
13
+ import re, sys, pathlib
14
+
15
+ p = pathlib.Path(sys.argv[1])
16
+ text = p.read_text(encoding="utf-8", errors="replace")
17
+ lines = text.splitlines()
18
+
19
+
20
+ def is_claude_line(line: str) -> bool:
21
+ s = line.strip()
22
+ if re.match(r"^Generated with(\s+\[Claude Code\])?", s, re.IGNORECASE):
23
+ return True
24
+ if "claude.ai/code" in s or "code.claude.com" in s:
25
+ return True
26
+ if re.match(r"^Co-Authored-By:\s*Claude\b", s, re.IGNORECASE):
27
+ return True
28
+ return False
29
+
30
+
31
+ # 末尾から Claude attribution 行を削除
32
+ while lines and (is_claude_line(lines[-1]) or lines[-1].strip() == ""):
33
+ if is_claude_line(lines[-1]):
34
+ lines.pop()
35
+ while lines and lines[-1].strip() == "":
36
+ lines.pop()
37
+ else:
38
+ lines.pop()
39
+
40
+ out = "\n".join(lines).rstrip() + "\n"
41
+ p.write_text(out, encoding="utf-8")
42
+ PY
43
+
44
+ exit 0
@@ -0,0 +1,45 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: ["**"]
6
+ pull_request:
7
+
8
+ jobs:
9
+ lint:
10
+ runs-on: ubuntu-latest
11
+ steps:
12
+ - uses: actions/checkout@v4
13
+ - uses: actions/setup-python@v5
14
+ with:
15
+ python-version: "3.12"
16
+ - name: Run ruff
17
+ run: pip install uv && uvx ruff check .
18
+
19
+ rust-test:
20
+ runs-on: ubuntu-latest
21
+ steps:
22
+ - uses: actions/checkout@v4
23
+ - uses: dtolnay/rust-toolchain@stable
24
+ - uses: Swatinem/rust-cache@v2
25
+ - name: Run Rust tests
26
+ run: cargo test
27
+
28
+ python-test:
29
+ runs-on: ubuntu-latest
30
+ strategy:
31
+ matrix:
32
+ python-version: ["3.10", "3.11", "3.12"]
33
+ steps:
34
+ - uses: actions/checkout@v4
35
+ - uses: dtolnay/rust-toolchain@stable
36
+ - uses: Swatinem/rust-cache@v2
37
+ - uses: actions/setup-python@v5
38
+ with:
39
+ python-version: ${{ matrix.python-version }}
40
+ - name: Install dependencies
41
+ run: pip install uv && uv sync --all-extras
42
+ - name: Run Python tests
43
+ run: .venv/bin/pytest tests/ -v --tb=short
44
+ env:
45
+ CI: "true"
@@ -0,0 +1,83 @@
1
+ name: Numerical Equivalence
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ schedule:
8
+ - cron: "0 2 * * 1"
9
+
10
+ jobs:
11
+ # R live comparison: non-blocking (R install ~15min)
12
+ equivalence-with-r:
13
+ runs-on: ubuntu-latest
14
+ if: github.event_name != 'schedule'
15
+ continue-on-error: true
16
+ steps:
17
+ - uses: actions/checkout@v4
18
+ - uses: r-lib/actions/setup-r@v2
19
+ with:
20
+ r-version: "4.4"
21
+ - name: Install R packages
22
+ run: |
23
+ Rscript -e "install.packages(
24
+ c('CausalImpact','jsonlite'),
25
+ repos='https://cloud.r-project.org'
26
+ )"
27
+ - uses: dtolnay/rust-toolchain@stable
28
+ - uses: Swatinem/rust-cache@v2
29
+ - uses: actions/setup-python@v5
30
+ with:
31
+ python-version: "3.12"
32
+ - name: Install Python dependencies
33
+ run: pip install uv && uv sync --all-extras
34
+ - name: Generate fresh R fixtures
35
+ run: Rscript scripts/generate_r_reference.R
36
+ - name: Run equivalence tests
37
+ run: .venv/bin/pytest tests/test_numerical_equivalence.py -v --tb=short
38
+ env:
39
+ CI: "true"
40
+
41
+ # Weekly: regenerate fixtures from R and auto-commit
42
+ regenerate-fixtures:
43
+ runs-on: ubuntu-latest
44
+ if: github.event_name == 'schedule'
45
+ permissions:
46
+ contents: write
47
+ steps:
48
+ - uses: actions/checkout@v4
49
+ with:
50
+ token: ${{ secrets.GITHUB_TOKEN }}
51
+ - uses: r-lib/actions/setup-r@v2
52
+ with:
53
+ r-version: "4.4"
54
+ - name: Install R packages
55
+ run: |
56
+ Rscript -e "install.packages(
57
+ c('CausalImpact','jsonlite'),
58
+ repos='https://cloud.r-project.org'
59
+ )"
60
+ - uses: dtolnay/rust-toolchain@stable
61
+ - uses: Swatinem/rust-cache@v2
62
+ - uses: actions/setup-python@v5
63
+ with:
64
+ python-version: "3.12"
65
+ - name: Install Python dependencies
66
+ run: pip install uv && uv sync --all-extras
67
+ - name: Regenerate R fixtures
68
+ run: Rscript scripts/generate_r_reference.R
69
+ - name: Run equivalence tests
70
+ run: .venv/bin/pytest tests/test_numerical_equivalence.py -v --tb=short
71
+ env:
72
+ CI: "true"
73
+ - name: Commit updated fixtures if changed
74
+ run: |
75
+ git config user.name "github-actions[bot]"
76
+ git config user.email "github-actions[bot]@users.noreply.github.com"
77
+ git add tests/fixtures/r_reference_*.json
78
+ if git diff --staged --quiet; then
79
+ echo "No fixture changes, skipping commit"
80
+ else
81
+ git commit -m "chore: regenerate R fixtures (weekly update)"
82
+ git push
83
+ fi
@@ -0,0 +1,70 @@
1
+ name: Release
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+
7
+ permissions:
8
+ contents: read
9
+
10
+ jobs:
11
+ build-wheels:
12
+ runs-on: ${{ matrix.os }}
13
+ strategy:
14
+ fail-fast: false
15
+ matrix:
16
+ include:
17
+ - os: ubuntu-latest
18
+ target: x86_64
19
+ - os: ubuntu-latest
20
+ target: aarch64
21
+ - os: macos-14
22
+ target: aarch64
23
+ - os: macos-latest
24
+ target: x86_64
25
+ - os: windows-latest
26
+ target: x64
27
+ steps:
28
+ - uses: actions/checkout@v4
29
+ - uses: actions/setup-python@v5
30
+ with:
31
+ python-version: "3.12"
32
+ - name: Build wheels
33
+ uses: PyO3/maturin-action@v1
34
+ with:
35
+ target: ${{ matrix.target }}
36
+ args: --release --out dist -i 3.10 3.11 3.12 3.13
37
+ manylinux: auto
38
+ - uses: actions/upload-artifact@v4
39
+ with:
40
+ name: wheels-${{ matrix.os }}-${{ matrix.target }}
41
+ path: dist/*.whl
42
+
43
+ build-sdist:
44
+ runs-on: ubuntu-latest
45
+ steps:
46
+ - uses: actions/checkout@v4
47
+ - name: Build sdist
48
+ uses: PyO3/maturin-action@v1
49
+ with:
50
+ command: sdist
51
+ args: --out dist
52
+ - uses: actions/upload-artifact@v4
53
+ with:
54
+ name: sdist
55
+ path: dist/*.tar.gz
56
+
57
+ publish:
58
+ needs: [build-wheels, build-sdist]
59
+ runs-on: ubuntu-latest
60
+ environment: pypi
61
+ permissions:
62
+ id-token: write
63
+ steps:
64
+ - uses: actions/download-artifact@v4
65
+ with:
66
+ path: dist
67
+ merge-multiple: true
68
+ - uses: pypa/gh-action-pypi-publish@release/v1
69
+ with:
70
+ packages-dir: dist/
@@ -0,0 +1,13 @@
1
+ target/
2
+ .venv/
3
+ __pycache__/
4
+ *.pyc
5
+ *.pyo
6
+ *.so
7
+ *.egg-info/
8
+ dist/
9
+ build/
10
+ .ruff_cache/
11
+ z-ai/
12
+ .claude/
13
+ *.DS_Store
@@ -0,0 +1 @@
1
+ 3.12
@@ -0,0 +1,65 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ We as members, contributors, and leaders pledge to make participation in our
6
+ community a harassment-free experience for everyone, regardless of age, body
7
+ size, visible or invisible disability, ethnicity, sex characteristics, gender
8
+ identity and expression, level of experience, education, socio-economic status,
9
+ nationality, personal appearance, race, religion, or sexual identity
10
+ and orientation.
11
+
12
+ We pledge to act and interact in ways that contribute to an open, welcoming,
13
+ diverse, inclusive, and healthy community.
14
+
15
+ ## Our Standards
16
+
17
+ Examples of behavior that contributes to a positive environment for our
18
+ community include:
19
+
20
+ - Demonstrating empathy and kindness toward other people
21
+ - Being respectful of differing opinions, viewpoints, and experiences
22
+ - Giving and gracefully accepting constructive feedback
23
+ - Accepting responsibility and apologizing to those affected by our mistakes,
24
+ and learning from the experience
25
+ - Focusing on what is best not just for us as individuals, but for the
26
+ overall community
27
+
28
+ Examples of unacceptable behavior include:
29
+
30
+ - The use of sexualized language or imagery, and sexual attention or
31
+ advances of any kind
32
+ - Trolling, insulting or derogatory comments, and personal or political attacks
33
+ - Public or private harassment
34
+ - Publishing others' private information, such as a physical or email
35
+ address, without their explicit permission
36
+ - Other conduct which could reasonably be considered inappropriate in a
37
+ professional setting
38
+
39
+ ## Enforcement Responsibilities
40
+
41
+ Community leaders are responsible for clarifying and enforcing our standards of
42
+ acceptable behavior and will take appropriate and fair corrective action in
43
+ response to any behavior that they deem inappropriate, threatening, offensive,
44
+ or harmful.
45
+
46
+ ## Scope
47
+
48
+ This Code of Conduct applies within all community spaces, and also applies when
49
+ an individual is officially representing the community in public spaces.
50
+
51
+ ## Enforcement
52
+
53
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
54
+ reported to the community leaders responsible for enforcement via GitHub Issues
55
+ or by contacting the maintainer directly.
56
+
57
+ All complaints will be reviewed and investigated promptly and fairly.
58
+
59
+ ## Attribution
60
+
61
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage],
62
+ version 2.0, available at
63
+ https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
64
+
65
+ [homepage]: https://www.contributor-covenant.org
@@ -0,0 +1,81 @@
1
+ # Contributing to bsts-causalimpact
2
+
3
+ Thank you for considering contributing to bsts-causalimpact.
4
+
5
+ ## Development Setup
6
+
7
+ ### Prerequisites
8
+
9
+ - Python 3.10+
10
+ - Rust toolchain (stable)
11
+ - uv (recommended) or pip
12
+
13
+ ### Getting Started
14
+
15
+ ```bash
16
+ git clone https://github.com/YuminosukeSato/bsts-causalimpact.git
17
+ cd bsts-causalimpact
18
+
19
+ # Install all dependencies including Rust extension
20
+ uv sync --all-extras
21
+
22
+ # Set up git hooks
23
+ git config core.hooksPath .githooks
24
+ ```
25
+
26
+ ### Running Tests
27
+
28
+ ```bash
29
+ # Full test suite
30
+ uv run pytest tests/ -v
31
+
32
+ # Rust unit tests
33
+ cargo test
34
+
35
+ # Lint check
36
+ uv run ruff check .
37
+ ```
38
+
39
+ ## Pull Request Workflow
40
+
41
+ 1. Create a feature branch from `main`
42
+ 2. Write tests first (TDD)
43
+ 3. Implement changes
44
+ 4. Ensure all tests pass and ruff reports no errors
45
+ 5. Open a PR with a clear description of changes
46
+
47
+ ### Commit Messages
48
+
49
+ Use conventional commit style:
50
+
51
+ - `feat:` new features
52
+ - `fix:` bug fixes
53
+ - `test:` test additions or changes
54
+ - `docs:` documentation changes
55
+ - `refactor:` code restructuring without behavior change
56
+
57
+ ### Test Requirements
58
+
59
+ - All new code must have tests
60
+ - Boundary values and edge cases must be covered
61
+ - Existing tests must not be weakened to make them pass
62
+ - Numerical equivalence tests (±3% tolerance with R) must stay green
63
+
64
+ ## Architecture Overview
65
+
66
+ ```
67
+ python/causal_impact/ # Python package
68
+ src/ # Rust Gibbs sampler (PyO3)
69
+ tests/ # pytest test suite
70
+ benchmarks/ # Performance benchmarks
71
+ ```
72
+
73
+ The Gibbs sampler runs in Rust via PyO3 bindings. Python handles data preparation, post-processing, plotting, and summary formatting.
74
+
75
+ ## Reporting Issues
76
+
77
+ Open an issue on GitHub with:
78
+
79
+ - Steps to reproduce
80
+ - Expected vs actual behavior
81
+ - Python version and OS