Skip to content

What a dummy argument may say: local-parameter bounds, lower bounds, generics, where masks, elementwise logicals - #25

Open
chenyueqi wants to merge 4 commits into
constant-intrinsicsfrom
tier0-gaps
Open

What a dummy argument may say: local-parameter bounds, lower bounds, generics, where masks, elementwise logicals#25
chenyueqi wants to merge 4 commits into
constant-intrinsicsfrom
tier0-gaps

Conversation

@chenyueqi

@chenyueqi chenyueqi commented Sep 4, 2026

Copy link
Copy Markdown
Member

Stacked on #22. Closes #17, #18, #19, #24. Found by the CLUBB extension's tier-0 units.

Full suite green. CLUBB tier 0 goes from 8/14 to 12/14 bit-exact on this branch (mean_adv, tridiag_lu_solvers, penta_lu_solvers, bicgstab_solvers; t_in_k_module gains its three generic specifics, new_pdf eight of nine subprograms). The two left are #20, complex values.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Cne4hrGgYqhTMzVgzJtXYd

chenyueqi and others added 3 commits September 3, 2026 19:52
A bound may name a local parameter of the subprogram (#18): CLUBB's
w_term_ma_zt_lhs declares integer, parameter :: t_above = 1, t_below = 2
and sizes weights_zt2zm(ngrdcol, nzm, t_above:t_below) with them. The
interface record folds such a bound to the parameter's literal value, and
says so under folded_bounds; the wrapper compiled with an undeclared name
before, and the sampler had no table for it.

A lower bound may not be one (#24): lhs(-2:2, ngrdcol, ndim) has five rows.
The flat adapter and the plain wrapper now declare the axis lb:ub, and the
bit-exact gate sizes it ub - lb + 1, so both sides hand the callee the
layout it was written for instead of two rows and silence.

A specific of a public generic is public through it (#17): tridiag_lu_solve
over three private specifics left nothing the flat wrapper could spell.
The record marks each specific public with public_via, and the adapter uses
and calls the generic name, which is the only one that resolves.

The where-construct's masks are scaffolding (#19): _wn and _we<d>_<n>, the
unclaimed remainder and a masked elsewhere's own mask, join _wm on the
read/write check's discard list; new_pdf's sort_roots reported them as
target-only reads and writes.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Cne4hrGgYqhTMzVgzJtXYd
…oo; re-exports go through the generic

CLUBB's new_pdf writes any( .not. l_calc_mixt_frac ) over a logical array,
and the emitter spelled Python's scalar not, which raises on an array. The
WHERE-mask rule -- ~, &, | -- now applies wherever an operand's rank is
above zero; a rank the semantics cannot settle keeps the scalar spelling.

The flat adapter re-exports every spellable subprogram of the module, and a
private specific of a public generic among them is re-exported under the
generic's name, which is the only one the module lets out. The first cut
mapped only the subprograms with a plan; t_in_k_module and the banded
solvers failed to build on the specifics' names.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Cne4hrGgYqhTMzVgzJtXYd
… generic

The record handed to the plain wrapper for the <module>_flat adapter
dropped the generic table, so a specific re-exported under its generic's
name was used and called under its own -- which the adapter does not let
out. The table survives for the chosen specifics. CLUBB's t_in_k_module
(4 subprograms), tridiag_lu_solvers (3) and penta_lu_solvers (2) go through
bit-exact on it.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Cne4hrGgYqhTMzVgzJtXYd
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Cne4hrGgYqhTMzVgzJtXYd
@chenyueqi chenyueqi added bug Something isn't working area:frontend Fortran parsing, interface extraction, constant folding area:flatten flat adapters for derived-type interfaces (flatten, recorder, plans) area:verifier the gates: static.rwset, differential.bitexact/tolerance, oracles found-by:clubb surfaced by the recast-clubb extension on CLUBB_core labels Sep 4, 2026

@chenyueqi chenyueqi left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review of #25 against two questions: generic or CLUBB-specific, and any change to an existing rule.

Genericity: pass. All five items are Fortran-language or engine-internal rules. _wm/_wn/_we<d>_<n> are the numpy emitter's own WHERE-mask temporaries (statements.py, already on main); the discard regex simply lagged the emitter, and the new test checks the negatives. CLUBB appears only in docstrings. (The KINDS_64 domain-name list this branch carries comes from #22; commented there.)

Existing rules: no test modified or deleted, all six test files are additions. lb:ub sizing agrees with the translation's existing lower-bound handling (rules/indexing.py _origin, subprograms.py local sizing, all untouched). public_via flows to every consumer of public (modules.py, numpy_anchor.py, flatten.py, bitexact.py), which is the right semantics but wider than the description says. Two gaps inline: the bound fold is partial for symmetric -nd:nd bounds and nothing refuses the leftover, and _array_valued falls back to the scalar spelling when rank cannot be settled (main's behavior, but the description does not say the new rule is not fail-closed). folded_bounds is recorded in the facts JSON only; a line in reading-the-evidence.md would make it findable.

if bound is None:
continue
name = str(bound).strip().lower()
if name in values:

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only a bare name folds, so dimension(-nd:nd, ...) becomes {"lb": "- nd", "ub": "3"}; the new test's lhs assertion documents exactly this and its comment says the leftover is "the wrapper's to refuse", but nothing refuses it: f2py.py::_extent spells - nd:3 into the wrapper verbatim (gfortran undeclared-symbol build failure, not an engine refusal) and bitexact.py harvests nd from the lb text as a free extent to redraw. -n:n is common Fortran (stencils, band matrices). Not a regression against main, but the description's "folded to the value" is half true for symmetric bounds. Suggest folding a negated name too, or refusing when one bound of an axis folded and the other did not.

Unsettled ranks fall back to the scalar spelling, as before."""
try:
return self.semantics.rank(node) > 0
except Exception: # rank refuses what it cannot settle

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Swallowing Unanalyzable here emits Python's scalar not/and/or for an operand whose rank the engine could not settle, and semantics.rank returns 0 for an undeclared Name without raising, so a whole-array logical use-imported from another module never reaches this branch at all and is spelled not x. At runtime that raises for len>1 arrays (loud) but not np.array([True]) is silently False. This is main's behavior, so the PR strictly improves coverage, but the rule is not fail-closed and the description does not say so; the docstring's "as before" is the only mention.

@chenyueqi

Copy link
Copy Markdown
Member Author

The places where this branch turns a refusal on main into a silent fallback are recorded apart from the review, in #32 (rows 5-6), so each is ruled on rather than merged by omission. A row there closes when the rule refuses again, records what it assumed in the evidence, or takes the assumption from the extension's configuration.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:flatten flat adapters for derived-type interfaces (flatten, recorder, plans) area:frontend Fortran parsing, interface extraction, constant folding area:verifier the gates: static.rwset, differential.bitexact/tolerance, oracles bug Something isn't working found-by:clubb surfaced by the recast-clubb extension on CLUBB_core

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant