Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 45 additions & 14 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,53 @@ on:
- '*'
jobs:
run-tests:
name: Run tests for ${{ matrix.os }} on ${{ matrix.python-version }}
name: Run tests for ${{ matrix.os }} (${{ matrix.shard }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
# The three estimation tests in tests/test_chs_estimate.py take about four
# minutes each; the rest of the suite takes about the same in total. They
# run on their own Linux runners; the other legs deselect them.
# yamllint disable rule:line-length
matrix:
os:
- ubuntu-latest
- macos-latest
- windows-latest
python-version:
- '3.14'
include:
- os: ubuntu-latest
shard: rest
pytest_args: >-
tests --cov-report=xml --cov=./
--deselect tests/test_chs_estimate.py::test_estimate_chs_returns_conforming_result
--deselect tests/test_chs_estimate.py::test_estimate_chs_provides_ml_inference
--deselect tests/test_chs_estimate.py::test_estimate_chs_enforces_user_fixed_constraint_value
- os: ubuntu-latest
shard: long-1
pytest_args: >-
tests/test_chs_estimate.py::test_estimate_chs_returns_conforming_result
--cov-report=xml --cov=./
- os: ubuntu-latest
shard: long-2
pytest_args: >-
tests/test_chs_estimate.py::test_estimate_chs_provides_ml_inference
--cov-report=xml --cov=./
- os: ubuntu-latest
shard: long-3
pytest_args: >-
tests/test_chs_estimate.py::test_estimate_chs_enforces_user_fixed_constraint_value
--cov-report=xml --cov=./
- os: macos-latest
shard: rest
pytest_args: >-
tests -m 'not long_running'
--deselect tests/test_chs_estimate.py::test_estimate_chs_returns_conforming_result
--deselect tests/test_chs_estimate.py::test_estimate_chs_provides_ml_inference
--deselect tests/test_chs_estimate.py::test_estimate_chs_enforces_user_fixed_constraint_value
- os: windows-latest
shard: rest
pytest_args: >-
tests -m 'not long_running'
--deselect tests/test_chs_estimate.py::test_estimate_chs_returns_conforming_result
--deselect tests/test_chs_estimate.py::test_estimate_chs_provides_ml_inference
--deselect tests/test_chs_estimate.py::test_estimate_chs_enforces_user_fixed_constraint_value
# yamllint enable rule:line-length
steps:
- uses: actions/checkout@v6
- uses: prefix-dev/setup-pixi@v0.9.4
Expand All @@ -35,15 +71,10 @@ jobs:
activate-environment: true
frozen: true
- name: Run pytest
if: runner.os != 'Linux' || matrix.python-version != '3.14'
shell: bash -l {0}
run: pixi run -e tests-cpu tests
- name: Run pytest with coverage
if: runner.os == 'Linux' && matrix.python-version == '3.14'
shell: bash -l {0}
run: pixi run -e tests-cpu tests-with-cov
run: pixi run -e tests-cpu pytest ${{ matrix.pytest_args }}
- name: Upload coverage report
if: runner.os == 'Linux' && matrix.python-version == '3.14'
if: runner.os == 'Linux'
uses: codecov/codecov-action@v5
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
Expand Down
3 changes: 3 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
---
# Specs, plans and audit artifacts under docs/superpowers are kept verbatim.
exclude: ^docs/superpowers/
repos:
- repo: meta
hooks:
Expand Down Expand Up @@ -37,6 +39,7 @@ repos:
- id: name-tests-test
args:
- --pytest-test-first
exclude: ^tests/stable_translog_reference\.py$
- id: no-commit-to-branch
args:
- --branch
Expand Down
44 changes: 42 additions & 2 deletions docs/reference_guides/transition_functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,45 @@ below.
Same as `translog` but clips state values at ±10^12 before computation. Use this when
states might grow very large and cause numerical overflow.

### stable_translog

Like `translog`, but every square and interaction is evaluated on a smoothly clipped
state, while the linear part is untouched:

$$
f_{t+1} = \sum_j \beta_j s_j + \sum_j \gamma_j g(s_j)^2 + \sum_{a<b} \delta_{ab} g(s_a) g(s_b) + c,
\qquad g(x) = \frac{x}{\left(1 + |x/\text{scale}|^{\text{power}}\right)^{1/\text{power}}}
$$

with defaults `scale=3.0` and `power=4`. Near zero $g(x) \approx x$ and the function
agrees with `translog` (within 1 % of the nonlinear terms at $|x| \le 1$). Every
nonlinear basis term is bounded by $\text{scale}^2$. For a deterministic fixed-matrix
law with a Schur-stable COMPLETE linear part and uniformly bounded remaining forcing,
iterates are bounded. This is not a certificate for changing matrices, control-function
corrections, Gaussian sample paths or the UKF. The scalar application examples have a
repelling translog fixed point, but a negative square coefficient alone is not enough
to establish that root structure.

Use `stable_translog` when the estimated technology is iterated for many periods
(simulations, laws of motion in life-cycle models), subject to those conditions.
`robust_translog` clips the whole input and hence also bounds deterministic output for
fixed coefficients, but can settle at enormous artificial levels and alters linear
dynamics. Neither name certifies the complete estimator or prevents all arithmetic overflow.

Two caveats. Observed factors in the state vector are clipped too; keep their scale
comparable to the latent factors or fix their nonlinear coefficients. And a `scale`
beyond the translog's own unstable fixed point can leave a second stable fixed point in
the tail; check the fixed points of your estimated equations before simulating. Other
values of `scale` and `power` work in direct calls. Estimator registration requires
complete parameter/identity companions and allow-lists for a new module-level string,
or a correctly registered factor-argument callable; a one-line vector wrapper alone
is insufficient. The string lookup uses defaults. Scale is measured in the declared
factor units, not automatically in standard deviations. Preserving a change of units
requires transforming the clipping scale too. Sigma-point and identification caveats
are stated in design section 2.4.

**Parameters**: identical to `translog`.

### linear_and_squares

Like `translog` but without interaction terms:
Expand Down Expand Up @@ -140,7 +179,7 @@ $$
## When to use the AF variants

The general `translog` and `log_ces` (and the other built-in production
functions: `linear`, `robust_translog`, `linear_and_squares`,
functions: `linear`, `robust_translog`, `stable_translog`, `linear_and_squares`,
`log_ces_with_constant`, `log_ces_general`) enumerate parameters over **all**
factors, including observed factors. For the CHS estimator this is the intended
behaviour: observed factors are allowed to enter the production function with
Expand All @@ -156,7 +195,8 @@ match AF equations (6) and (7) respectively.

To make the leakage visible, `validate_af_model` emits a loud `UserWarning` when a
built-in production transition (`linear`, `linear_and_squares`, `translog`,
`robust_translog`, `log_ces`, `log_ces_with_constant`, `log_ces_general`) is used
`robust_translog`, `stable_translog`, `log_ces`, `log_ces_with_constant`,
`log_ces_general`) is used
on a non-endogenous production factor while observed factors are present. The
warning is not an error — intentionally-leaky models still run — but it flags the
wrong-estimand risk. Switch to `translog_af` / `log_ces_af`, or pin every
Expand Down
Loading
Loading