Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
b69d2e9
Regenerate R parity cache for NNS 13.1
OVVO-Financial Jul 14, 2026
17bb20f
Update R 13.1 copula fixtures
OVVO-Financial Jul 14, 2026
78ac59c
Apply PR118 deterministic fixes
OVVO-Financial Jul 14, 2026
b9cbb12
Complete PR118 deterministic repair workflow
OVVO-Financial Jul 14, 2026
39959f4
Align Python parity with R NNS 13.1 copula anchor
github-actions[bot] Jul 14, 2026
7e12c73
Diagnose PR118 seasonal causation lags
OVVO-Financial Jul 14, 2026
da37a18
Apply PR118 source parity fixes
OVVO-Financial Jul 14, 2026
f684bf2
Match R 13.1 seasonality and Spearman precision
github-actions[bot] Jul 14, 2026
fad973d
Run CI for PR118 source parity fixes
OVVO-Financial Jul 14, 2026
c8687d0
Run PR118 targeted parity diagnostics
OVVO-Financial Jul 14, 2026
b0d1541
Enable PR118 targeted diagnostics on pull requests
OVVO-Financial Jul 14, 2026
95ae094
Add PR118 seasonal lag diagnostics
OVVO-Financial Jul 14, 2026
67733c4
Run PR118 live R internal diagnostics
OVVO-Financial Jul 14, 2026
f65aab9
Add copula smoke to live R diagnostics
OVVO-Financial Jul 14, 2026
1529702
Apply PR118 VAR and cache-backed test fixes
OVVO-Financial Jul 14, 2026
95b4ea7
Match R 13.1 all-method stack coefficients
github-actions[bot] Jul 14, 2026
bf260b3
Validate PR118 VAR and cache-backed test fixes
OVVO-Financial Jul 14, 2026
63999b3
Focus PR118 live R diagnostics on unresolved cases
OVVO-Financial Jul 14, 2026
a95a80d
Apply PR118 final parity fixes
OVVO-Financial Jul 14, 2026
239721b
Match R extended-precision normalization semantics
github-actions[bot] Jul 14, 2026
3b32d2d
Fix PR118 provenance manifest and stale dy_d parity expectation
claude Jul 14, 2026
69e08e1
Correct stale period7 NNS.caus cache entry to live R 13.1
claude Jul 14, 2026
c0289a5
Correct stale causal_matrix NNS.caus cache entry to live R 13.1
claude Jul 14, 2026
b62f712
Widen causal-matrix net tolerance for direction-ambiguous ts pairs
claude Jul 14, 2026
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
66 changes: 66 additions & 0 deletions .github/workflows/pr118-live-r-debug.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
name: PR118 live R internal diagnostics
on:
pull_request:
branches: [main]
permissions:
contents: read
jobs:
diagnose:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.11'
- uses: r-lib/actions/setup-r@v2
with:
r-version: release
use-public-rspm: true
- run: |
sudo apt-get update
sudo apt-get install -y libgsl-dev libjpeg-dev libpng-dev libtiff5-dev libfreetype6-dev libharfbuzz-dev libfribidi-dev xorg-dev
curl -fL https://raw.githubusercontent.com/OVVO-Financial/NNS/1d4d1e9ccc872ccc25eacfc7153a5ff8c4abd172/NNS_13.1.tar.gz -o /tmp/NNS_13.1.tar.gz
mkdir -p /tmp/nns && tar -xzf /tmp/NNS_13.1.tar.gz -C /tmp/nns --strip-components=1
Rscript -e "options(repos=c(CRAN='https://cloud.r-project.org')); install.packages(c('remotes','jsonlite')); remotes::install_deps('/tmp/nns', dependencies=NA, upgrade='never')"
R CMD INSTALL /tmp/NNS_13.1.tar.gz
python -m pip install -U pip
python -m pip install build scikit-build-core nanobind pytest 'numpy<2.5' scipy hypothesis pytest-benchmark pytest-xdist
python -m pip install -e . --force-reinstall --no-deps
- name: Compare unresolved internals
continue-on-error: true
run: |
Rscript - <<'RS' > live-r-debug.txt 2>&1
library(NNS)
a <- c(1,2,3,4,5); b <- c(1,2,1,4,3); cc <- c(2,1,3,5,4)
cat('R copula3 continuous',NNS.copula(cbind(a,b,cc),continuous=TRUE,plot=FALSE),'\n')
cat('R copula3 discrete',NNS.copula(cbind(a,b,cc),continuous=FALSE,plot=FALSE),'\n')
dx <- cbind(c(-2,-1,0,1,2),c(1,3,5,7,9)); dy <- dx[,1]^2 + sin(dx[,2])
cat('R dy1 first',dy.d_(dx,dy,wrt=1,eval.points='mean',messages=FALSE)$First,'\n')
cat('R dy1 second',dy.d_(dx,dy,wrt=1,eval.points='mean',messages=FALSE)$Second,'\n')
cat('R dy2 first',dy.d_(dx,dy,wrt=2,eval.points='mean',messages=FALSE)$First,'\n')
cat('R dy2 second',dy.d_(dx,dy,wrt=2,eval.points='mean',messages=FALSE)$Second,'\n')
t <- 1:70; x <- sin(2*pi*t/7); y <- c(tail(x,1),head(x,-1)) + .05*cos(t/3); tau <- 7
make_tau <- function(v,tau){n<-length(v);z<-vector('list',tau+1);for(i in 0:tau)z[[i+1]]<-v[(tau-i+1):(n-i)];do.call(cbind,z)}
xn <- unlist(NNS.norm(make_tau(x,tau))[,1]); yn <- unlist(NNS.norm(make_tau(y,tau))[,1]); xy <- NNS.norm(cbind(xn,yn))
cat('R xn head',head(xn,8),'\n'); cat('R yn head',head(yn,8),'\n'); cat('R xy head',as.numeric(head(xy,4)),'\n')
cat('R Uni xy',NNS:::Uni.caus(x,y,tau,plot=FALSE),'\n'); cat('R Uni yx',NNS:::Uni.caus(y,x,tau,plot=FALSE),'\n'); cat('R caus',NNS.caus(x,y,tau='ts',plot=FALSE),'\n')
RS
python - <<'PY' >> live-r-debug.txt 2>&1
import numpy as np
from nns import dy_d,nns_causation,nns_copula,nns_norm
from nns.causation import _tau_normalized,_uni_caus
a=np.array([1,2,3,4,5.]); b=np.array([1,2,1,4,3.]); c=np.array([2,1,3,5,4.]); a3=np.column_stack((a,b,c))
print('PY copula3 continuous',nns_copula(a3,continuous=True)); print('PY copula3 discrete',nns_copula(a3,continuous=False))
dx=np.column_stack((np.array([-2,-1,0,1,2.]),np.array([1,3,5,7,9.]))); dy=dx[:,0]**2+np.sin(dx[:,1])
print('PY dy1',dy_d(dx,dy,wrt=1,eval_points='mean')); print('PY dy2',dy_d(dx,dy,wrt=2,eval_points='mean'))
t=np.arange(1,71,dtype=float); x=np.sin(2*np.pi*t/7); y=np.roll(x,1)+.05*np.cos(t/3)
xn,yn=_tau_normalized(x,y,7); xy=nns_norm(np.column_stack((xn,yn)))
print('PY xn head',xn[:8].tolist()); print('PY yn head',yn[:8].tolist()); print('PY xy head',xy[:4].ravel(order='F').tolist())
print('PY Uni xy',_uni_caus(x,y,7)); print('PY Uni yx',_uni_caus(y,x,7)); print('PY caus',list(nns_causation(x,y,tau='ts').values()))
PY
- uses: actions/upload-artifact@v4
if: always()
with:
name: pr118-live-r-debug
path: live-r-debug.txt
if-no-files-found: warn
55 changes: 55 additions & 0 deletions .github/workflows/pr118-targeted-diagnostics.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
name: PR118 targeted parity diagnostics
on:
pull_request:
branches: [main]
push:
branches: [automation/r-cache-nns-13.1]
permissions:
contents: read
jobs:
diagnose:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.11'
- run: |
python -m pip install -U pip
python -m pip install build scikit-build-core nanobind pytest 'numpy<2.5' scipy hypothesis pytest-benchmark pytest-xdist
python -m pip install -e . --force-reinstall --no-deps
- name: Run targeted parity
continue-on-error: true
run: |
NNS_R_CACHE_ONLY=1 python -m pytest -q \
tests/parity/test_original_dependence.py \
tests/parity/test_diff.py \
tests/parity/test_r13_smoke.py \
tests/parity/test_var.py \
tests/parity/test_causation.py > pr118-targeted.log 2>&1
- name: Record seasonal lag diagnostics
run: |
python - <<'PY' > pr118-seasonal.txt
import numpy as np
from nns import nns_causation
from nns.seasonality import nns_seas
t=np.arange(1,71,dtype=float)
x=np.sin(2*np.pi*t/7)
y=np.roll(x,1)+0.05*np.cos(t/3)
print('x periods',nns_seas(x,plot=False)['periods'].tolist())
print('y periods',nns_seas(y,plot=False)['periods'].tolist())
for tx in range(1,9):
for ty in range(1,9):
a=nns_causation(x,y,tau=ty)
b=nns_causation(y,x,tau=tx)
print('same_tau',tx,ty,list(a.values()),list(b.values()))
t=np.arange(1,81,dtype=float)
z=[np.sin(2*np.pi*t/5),np.sin(2*np.pi*t/6+0.2),np.sin(2*np.pi*t/7+0.5)]
print('matrix periods',[nns_seas(v,plot=False)['periods'].tolist() for v in z])
PY
- uses: actions/upload-artifact@v4
with:
name: pr118-targeted-diagnostics
path: |
pr118-targeted.log
pr118-seasonal.txt
2 changes: 1 addition & 1 deletion src/nns/diff.py
Original file line number Diff line number Diff line change
Expand Up @@ -556,7 +556,7 @@ def _nns_copula_matrix(values: NDArray[np.float64]) -> float:

discrete_d_pm = _dpm_nd(data, target, 0.0, norm=True)
continuous_d_pm = _dpm_nd(data, target, 1.0, norm=True)
independent_d_pm = 1.0 - (0.5**n_cols)
independent_d_pm = 1.0 - 2.0 * (0.5**n_cols)
n_dim_discrete_dep = abs(discrete_d_pm - independent_d_pm) / independent_d_pm
n_dim_continuous_dep = abs(continuous_d_pm - independent_d_pm) / independent_d_pm

Expand Down
2 changes: 1 addition & 1 deletion src/nns/norm.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ def nns_norm(
if len({item.size for item in series}) > 1:
return _norm_unequal_series(series)
values = _as_matrix(np.column_stack(series), "x")
means = np.mean(values, axis=0)
means = np.mean(values.astype(np.longdouble), axis=0).astype(np.float64)
means = means.copy()
means[means == 0.0] = 1e-10
ratio_grid = means[:, np.newaxis] * (1.0 / means[np.newaxis, :])
Expand Down
20 changes: 7 additions & 13 deletions src/nns/seasonality.py
Original file line number Diff line number Diff line change
Expand Up @@ -225,10 +225,7 @@ def _cv_stat(values: NDArray[np.float64], var_cov: float, exact_cv: bool) -> flo


def _mean(values: NDArray[np.float64]) -> float:
if values.size >= 16:
mean = float(np.sum(values)) / float(values.size)
if abs(mean) > 1e-12:
return mean
# Match R NNS_seas_cpp::vec_mean exactly: sequential accumulation.
total = 0.0
for value in values:
total += float(value)
Expand All @@ -243,15 +240,12 @@ def _mean_exact(values: NDArray[np.float64]) -> float:


def _sample_sd_from_mean(values: NDArray[np.float64], mean: float, *, exact: bool = False) -> float:
if not exact and values.size >= 16 and abs(mean) > 1e-12:
ss = float(np.dot(values, values)) - float(values.size) * mean * mean
if ss < 0.0:
ss = 0.0
else:
ss = 0.0
for value in values:
delta = float(value) - mean
ss += delta * delta
del exact
# Match R NNS_seas_cpp::vec_sd exactly: sequential squared deviations.
ss = 0.0
for value in values:
delta = float(value) - mean
ss += delta * delta
return math.sqrt(ss / float(values.size - 1))


Expand Down
4 changes: 2 additions & 2 deletions src/nns/stack.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ def _spearman_scores(x: NDArray[np.float64], y: NDArray[np.float64]) -> NDArray[
y_rank = _rank_average(y)
scores = np.empty(x.shape[1], dtype=np.float64)
for col in range(x.shape[1]):
scores[col] = abs(round(_pearson(_rank_average(x[:, col]), y_rank), 2))
scores[col] = abs(_pearson(_rank_average(x[:, col]), y_rank))
scores[~np.isfinite(scores)] = 0.0
return scores

Expand Down Expand Up @@ -645,7 +645,7 @@ def caus_coef() -> NDArray[np.float64]:
coef = np.ones(p, dtype=np.float64)
elif dim_red_value == "all":
coef = np.mean(
np.column_stack((caus_coef(), dep_coef(), cor_coef(), np.ones(p))), axis=1
np.column_stack((caus_coef(), dep_coef(), cor_coef())), axis=1
)
else:
raise ValueError("Unsupported [dim.red.method].")
Expand Down
6 changes: 3 additions & 3 deletions sync/nns_source.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
{
"r_repo": "OVVO-Financial/NNS",
"r_commit": "905b8bbd42b3236bf88aba7f18df7a9a378dbd7b",
"r_version": "13.0",
"r_src_tree_hash": "654e411bd4e8caabfd57a1a4190eb1d97411e059",
"r_commit": "1d4d1e9ccc872ccc25eacfc7153a5ff8c4abd172",
"r_version": "13.1",
"r_src_tree_hash": "1c82fa36a4af3ce6359cc34b3d841afa6bdd1815",
"core_repo": "OVVO-Financial/NNS-core",
"core_commit": "cfc25a3469df6460f9224fb976fcb58de9d58068",
"python_repo": "OVVO-Financial/NNS-python",
Expand Down
1 change: 1 addition & 0 deletions sync/pr118-ci-trigger.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Temporary CI trigger for PR #118 after VAR and cache-backed test fixes. Remove after validation.
3 changes: 1 addition & 2 deletions tests/_r.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@
_CACHE_PATH = Path(__file__).with_name("_r_cache.json")
_LOCK_PATH = _CACHE_PATH.with_suffix(".lock")
_SCHEMA_VERSION = 1
_NNS_VERSION = "13.1-racine-hastie-r2"

_NNS_VERSION = '13.1'
JsonValue: TypeAlias = None | str | float | list["JsonValue"] | dict[str, "JsonValue"]
RValue: TypeAlias = (
None | float | str | list[str | None] | NDArray[np.float64] | dict[str, "RValue"]
Expand Down
Loading
Loading