Metadata-Version: 2.4
Name: stresspy
Version: 0.0.2
Summary: Core numerical routines for the Geometric Stress Criterion
Author: Dan James
Requires-Python: >=3.10
Description-Content-Type: text/markdown
Requires-Dist: numpy>=1.24

# StressPy v0.1: Core Developer Guide

`stresspy` is an early reference implementation of the deterministic numerical core of the **Geometric Stress Criterion (GSC)**. It decomposes a model–data discrepancy into components that are locally accessible and inaccessible through variation of the model's adjustable parameters.

Version 0.1 is intentionally small. It does not fit models, infer the meaning of uploaded data, construct ODE Jacobians, or perform bootstrap calibration. Those capabilities can be added around the core after the central calculation has been independently tested.

---

## 1. Mathematical Convention

At a specified parameter point $\hat{\theta}$, let

$$r = y - f(\hat{\theta})$$

be the model–data discrepancy and let

$$J = \left.\frac{\partial f}{\partial x}\right\vert{}_{\hat{\theta}}$$

be the Jacobian with respect to the chosen parameter coordinates $x$.

After applying an observation-space whitening transformation $L$, GSC uses

$$r_W = Lr, \qquad J_W = LJ$$

If $U_r$ contains the retained left singular vectors of $J_W$, then

$$r_{\parallel,W} = U_r U_r^\top r_W, \qquad r_{\perp,W} = r_W - r_{\parallel,W}$$

The reported stresses are

$$S_{\mathrm{total}} = \Vert{}r_W\Vert{}_2^2, \qquad S_{\parallel} = \Vert{}r_{\parallel,W}\Vert{}_2^2, \qquad S_{\perp} = \Vert{}r_{\perp,W}\Vert{}_2^2$$

with normal fraction

$$F_{\perp} = \frac{S_{\perp}}{S_{\mathrm{total}}}$$

The minimum-norm local repair is

$$\Delta x = V_r \Sigma_r^{-1} U_r^\top r_W$$

Under the local linear approximation,

$$r - J \Delta x = r_\perp$$

The repair is minimum-norm only in the coordinates used to construct $J$. Its magnitude is therefore coordinate-dependent. Local tangent accessibility also does not imply that the corresponding finite nonlinear step is practical.

---

## 2. What the Core Returns

`decompose()` returns a `GSCResult` object containing:

| Result Field | Meaning |
| :--- | :--- |
| `total_stress` | Total squared discrepancy in the selected metric |
| `tangent_stress` | Squared tangent-accessible component |
| `normal_stress` | Squared locally inaccessible component |
| `normal_fraction` | `normal_stress` / `total_stress` |
| `rank` | Number of retained Jacobian singular directions |
| `rank_threshold` | Singular-value threshold used for retention |
| `singular_values` | Singular spectrum of the whitened Jacobian |
| `repair_vector` | Minimum-norm local repair in the supplied coordinates |
| `repair_norm` | Euclidean norm of that coordinate repair |
| `condition_number` | Condition number of the retained tangent system |
| `component vectors` | Residual, tangent and normal vectors in weighted and original coordinates |

*Note: When the total discrepancy is exactly zero, `normal_fraction` is reported as `nan`, because the ratio is mathematically undefined.*

---

## 3. Basic Usage

```python
import numpy as np
from stresspy import decompose

J = np.array([
    [1.0, 0.0],
    [1.0, 1.0],
    [0.0, 1.0],
])

predicted = np.array([1.0, 2.0, 1.0])
observed = np.array([1.1, 1.9, 0.9])
sigma = np.array([0.1, 0.1, 0.1])

result = decompose(
    observed=observed,
    predicted=predicted,
    jacobian=J,
    sigma=sigma,
    rank_rtol=1e-8,
)

print(result.rank)
print(result.total_stress)
print(result.tangent_stress)
print(result.normal_stress)
print(result.normal_fraction_pct)
print(result.repair_vector)
