Skip to content

OUQBase: evaluate Inequality probability events as Bool comparisons - #60

Merged
ChrisRackauckas merged 11 commits into
SciML:mainfrom
ChrisRackauckas-Claude:agent/54-ouqbase-inequality-bool
Oct 3, 2026
Merged

ChrisRackauckas merged 11 commits into
SciML:mainfrom
ChrisRackauckas-Claude:agent/54-ouqbase-inequality-bool

Conversation

@ChrisRackauckas-Claude

@ChrisRackauckas-Claude ChrisRackauckas-Claude commented Sep 26, 2026 •

Copy link
Copy Markdown
Member

Summary

Stacked on #59 (merge after it). ≲/≳ build Symbolics.Inequality constraint objects, not Boolean comparisons; Symbolics 7 leaving them as unfolded isless(...) inside evaluate is a design difference, not an upstream bug. This PR maps Inequality(lhs, rhs, leq|geq) to lhs <= rhs / lhs >= rhs via boolean_probability_event before probability-oracle evaluation (canonical moments and Winkler paths), so Flood-style events become Bool.

Verification

Fail-before / pass-after

Before (#59 tip sources, new tests):

  • Unit: UndefVarError: boolean_probability_event not defined
  • Flood test_canonical_moments.jl:29: MethodError: isapprox(::BasicSymbolic, ::Float64)

After:

Test Summary: | Pass  Total     Time
smoke         |   32     32  1m03.7s

(includes unit conversion + Flood canonical-moments objective)

OUQBase Core / QA

julia +lts (1.10.12):

promote_symtype operators |   22     22
Flood Problem (canonical moments objective) |    1      1
Testing OUQBase tests passed
Quality Assurance |   16     16
Testing OUQBase tests passed

julia +1 (1.13.0):

promote_symtype operators |   22     22
Flood Problem (canonical moments objective) |    1      1
Testing OUQBase tests passed
Quality Assurance |   18     18
Testing OUQBase tests passed

What I did NOT verify

  • End-to-end optimizer solves beyond the Flood objective smoke at the fixture point.
  • Root-package / Downgrade workflows.

Reviewer pushback

  • Whether converting at extract time (current) vs inside the per-sample evaluate closure is clearer.
  • Whether any other probability path still evaluates a raw Inequality.

Part of #54. Stacked on #59 — merge after #59.

Please ignore this draft until reviewed by @ChrisRackauckas.

Risk assessment

Harness: Cursor Agent CLI 2026.09.26-dd393fe; model: auto; transcript: /home/crackauc/sandbox/agent-jobs/OptimalUncertaintyQuantification.jl/jobs/54-cursor/log.txt on amdci2.julia.csail.mit.edu

Update (Codex gpt-6-astra round-1 CHANGES)

Stopped using non-public Symbolics.leq / Symbolics.geq. Inequality dispatch now compares relational_op against the values from the public constructors (lhs ≲ rhs).relational_op / (lhs ≳ rhs).relational_op (also applied in the Winkler Jump helper). Removed :leq / :geq from the QA qualified-accesses ignore list. Rebased onto fixed #59 (ModelingToolkitBase.getdefault, no ownership ignore).

Re-verification (OPTIMALUNCERTAINTYQUANTIFICATION_TEST_GROUP)

julia +lts (1.10.12):

promote_symtype operators |   31     31
Flood Problem (canonical moments objective) |    1      1
Testing OUQBase tests passed
Quality Assurance |   16     16
Testing OUQBase tests passed

julia +1 (1.13.0):

promote_symtype operators |   31     31
Flood Problem (canonical moments objective) |    1      1
Testing OUQBase tests passed
Quality Assurance |   18     18
Testing OUQBase tests passed

What I did NOT verify

Harness: Cursor Agent CLI 2026.09.26-dd393fe; model: auto; transcript: /home/crackauc/sandbox/agent-jobs/OUQ-b/jobs/54-cursor/log.txt on amdci2.julia.csail.mit.edu

Risk assessment

  • Risk: medium
  • Blast radius: OUQBase only. Specifically: how the 𝔼/ℙ/𝟙 operator terms are built, random-variable group resolution (get_ordered_group_names now looks inside 𝔼/ℙ and inside ≲/≳ inequalities), raw-moment order parsing, and probability-objective evaluation in the canonical-moments oracle path and the Winkler Symbolic path. Winkler's JuMP path is unaffected because it still reads the raw condition (only(arguments(objective._obj))). The PR's base is main, not Fix OUQBase 𝔼/ℙ SymbolicUtils Operator ambiguity (separate from #54 floor) #59, so merging it also brings in all 8 of Fix OUQBase 𝔼/ℙ SymbolicUtils Operator ambiguity (separate from #54 floor) #59's commits. That includes a new direct dependency on ModelingToolkitBase (compat 1.50).
  • Evidence: On head 133a780, 2 checks fail. Both are pre-existing, because the same jobs fail with the same errors on the latest main push runs (013f14a, 2026-09-16):
    • Downgrade Sublibraries / test (lib/DiscreteMeasures): 5 errors, ArgumentError: intersect is purposely not supported for intervals at discrete_measures_tests.jl:94-98. Main shows the same 5 errors on the same lines. Pre-existing, and the PR does not touch lib/DiscreteMeasures.
    • tests / QA (julia 1) / Tests - QA (Julia 1): the root package's no_implicit_imports errors, and public API has docstrings and No unapproved public reexports fail. The totals are 18 passed / 2 failed / 1 errored, which matches main exactly. Pre-existing.
    • Every other check passes, including OUQBase Core on lts/1/pre, OUQBase QA, root Core ×4, Docs, Runic and typos. Downgrade Sublibraries / test (lib/OUQBase) fails on main and passes here, so that one is an improvement.
    • No regressions. One caveat: Fix OUQBase 𝔼/ℙ SymbolicUtils Operator ambiguity (separate from #54 floor) #59's own head (630a206) is red on sublibraries / lib/OUQBase / Julia {1,lts} / Tests - Core with MethodError: isapprox(::BasicSymbolic, ::Float64) at test_canonical_moments.jl:29. Following the description's advice to merge Fix OUQBase 𝔼/ℙ SymbolicUtils Operator ambiguity (separate from #54 floor) #59 first would leave main red on OUQBase Core until this PR lands.
  • Independent review: Devin CLI (Mac) / fusion-claude-opus-5-5-high-sidekick-swe-2-medium rated it medium, medium confidence: CI shows no regressions and the new tests fail before the fix and pass after. However, this is a stacked PR that folds in all of Fix OUQBase 𝔼/ℙ SymbolicUtils Operator ambiguity (separate from #54 floor) #59's symbolic-internals rework, and the Winkler Symbolic change has no end-to-end test (the author says a pre-existing getbounds(::OrderedSet) failure blocks one).
  • Merge: needs human review. Findings:
    1. Stacked PR. The diff contains all of Fix OUQBase 𝔼/ℙ SymbolicUtils Operator ambiguity (separate from #54 floor) #59, which is still open and red on its own. The advised order ("merge after Fix OUQBase 𝔼/ℙ SymbolicUtils Operator ambiguity (separate from #54 floor) #59") would leave main temporarily red. Merging this PR alone, or retargeting it onto Fix OUQBase 𝔼/ℙ SymbolicUtils Operator ambiguity (separate from #54 floor) #59's branch, avoids that.
    2. Undisclosed new dependency. The new direct dependency ModelingToolkitBase (compat 1.50, SciML/MIT) is not mentioned or license-noted in this PR's description. OUQBase's version is not bumped either.
    3. Internal field access remains. .relational_op is still read directly from Symbolics.Inequality. Comparing it against the value from the public ≲/≳ constructors avoids naming Symbolics.leq/geq, but it still depends on an undocumented struct field. The QA ignores for promote_symtype, isbinop, evaluate, BasicSymbolic, Operator, Term, symtype and value are still in place (pre-existing).
    4. Behavior changes in exported code, no SemVer bump. Exported 𝔼/ℙ/𝟙 now build terms with SymbolicUtils.term instead of Term{symtype(x)}. get_raw_moment_order now errors on any left-hand side that isn't a 𝔼 term, and build_raw_moment_sequence converts the right-hand side to Float64. These look like bug fixes and all touched helpers are unexported, but a human should confirm none of it counts as a public behavior change.
    5. Tests are strengthened, not weakened. The QA ignore list got shorter (:geq, :leq, :getdefault removed) and there are no skips or loosened tolerances. Two small issues in the new test file: d = Dict(...) is unused, and one assertion checks that Symbolics leaves isless unfolded, which will break if Symbolics changes that behavior.
    6. Not verified by the author: end-to-end optimizer solves, the Winkler optimizer build, and root/Downgrade workflows (all stated in the PR description). The PR has no human review comments.

🤖 Risk assessment posted by an AI agent (fleet master) — harness: Devin CLI (Mac) / fusion-claude-opus-5-5-high-sidekick-swe-2-medium; dispatched by Claude Code head, model claude-opus-5-5[1m]
Conversation: local Claude Code session 3cd6500a-1f81-46b5-ac0b-c466e15b6a53 on Chris's Mac (session ID, no URL)

ChrisRackauckas and others added 10 commits September 26, 2026 08:43
Add Type-specialized promote_symtype methods so SymbolicUtils Operator
dispatch is unambiguous, and build terms via SymbolicUtils.term so the
SymVariant Term API is used instead of Term{Real}.

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: Cursor Agent <noreply@cursor.com>
Agent-Harness: Cursor Agent CLI 2026.09.26-dd393fe
Agent-Model: auto
Agent-Session: local session, transcript at /home/crackauc/sandbox/agent-jobs/OptimalUncertaintyQuantification.jl/jobs/54-cursor/log.txt on amdci2.julia.csail.mit.edu
Symbolics treats Operator applications as variable leaves, so
get_variables(𝔼(Q^n)) returned 𝔼(Q^n) and group lookup failed. Unwrap
OUQ operators and collect variables from their arguments.

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: Cursor Agent <noreply@cursor.com>
Agent-Harness: Cursor Agent CLI 2026.09.26-dd393fe
Agent-Model: auto
Agent-Session: local session, transcript at /home/crackauc/sandbox/agent-jobs/OptimalUncertaintyQuantification.jl/jobs/54-cursor/log.txt on amdci2.julia.csail.mit.edu
Replace the broken @rule chain with TermInterface extraction, and unwrap
Const-wrapped numeric RHS values before filling Float64 moment sequences.

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: Cursor Agent <noreply@cursor.com>
Agent-Harness: Cursor Agent CLI 2026.09.26-dd393fe
Agent-Model: auto
Agent-Session: local session, transcript at /home/crackauc/sandbox/agent-jobs/OptimalUncertaintyQuantification.jl/jobs/54-cursor/log.txt on amdci2.julia.csail.mit.edu
Cover promote_symtype for 𝔼_/ℙ_, underlying RV extraction through 𝔼(Q^n),
and raw moment order parsing.

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: Cursor Agent <noreply@cursor.com>
Agent-Harness: Cursor Agent CLI 2026.09.26-dd393fe
Agent-Model: auto
Agent-Session: local session, transcript at /home/crackauc/sandbox/agent-jobs/OptimalUncertaintyQuantification.jl/jobs/54-cursor/log.txt on amdci2.julia.csail.mit.edu
Unwrap Inequality/Equation args in underlying_random_variables so
ℙ(Q ≳ c)/ℙ(Q ≲ c) discover the RV (Flood fixtures); drop unused Chain;
import Operator from SymbolicUtils (owner).

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: Cursor Agent <noreply@cursor.com>
Agent-Harness: Cursor Agent CLI 2026.09.26-dd393fe
Agent-Model: auto
Agent-Session: local session, transcript at /home/crackauc/sandbox/agent-jobs/OptimalUncertaintyQuantification.jl/jobs/54-cursor/log.txt on amdci2.julia.csail.mit.edu
Check isinteger before Int(...) so 𝔼(Q^2.5) raises the descriptive
raw-moment error instead of InexactError.

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: Cursor Agent <noreply@cursor.com>
Agent-Harness: Cursor Agent CLI 2026.09.26-dd393fe
Agent-Model: auto
Agent-Session: local session, transcript at /home/crackauc/sandbox/agent-jobs/OptimalUncertaintyQuantification.jl/jobs/54-cursor/log.txt on amdci2.julia.csail.mit.edu
get_variables returns the leaf itself for z(t), a[1], and Differential(t)(z);
treat that as a base case so group lookup does not StackOverflow.

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: Cursor Agent <noreply@cursor.com>
Agent-Harness: Cursor Agent CLI 2026.09.26-dd393fe
Agent-Model: auto
Agent-Session: local session, transcript at /home/crackauc/sandbox/agent-jobs/OptimalUncertaintyQuantification.jl/jobs/54-cursor/log.txt on amdci2.julia.csail.mit.edu
Qualified ModelingToolkit.getdefault failed
check_all_qualified_accesses_via_owners; route through the
owner package (direct dep) and drop the QA ownership ignore.

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: Cursor Agent <noreply@cursor.com>
Agent-Harness: Cursor Agent CLI 2026.09.26-dd393fe
Agent-Model: auto
Agent-Session: local session, transcript at /home/crackauc/sandbox/agent-jobs/OUQ-b/jobs/54-cursor/log.txt on amdci2.julia.csail.mit.edu
≲/≳ build Symbolics.Inequality constraint objects, not Bools.
Convert leq/geq to lhs <= rhs / lhs >= rhs before evaluate so
Flood canonical-moments objectives return numeric probabilities.

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: Cursor Agent <noreply@cursor.com>
Agent-Harness: Cursor Agent CLI 2026.09.26-dd393fe
Agent-Model: auto
Agent-Session: local session, transcript at /home/crackauc/sandbox/agent-jobs/OptimalUncertaintyQuantification.jl/jobs/54-cursor/log.txt on amdci2.julia.csail.mit.edu
Avoid non-public Symbolics.leq/geq; compare against
(x ≲ y).relational_op / (x ≳ y).relational_op from the
public constructors, and drop those names from the QA ignore.

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: Cursor Agent <noreply@cursor.com>
Agent-Harness: Cursor Agent CLI 2026.09.26-dd393fe
Agent-Model: auto
Agent-Session: local session, transcript at /home/crackauc/sandbox/agent-jobs/OUQ-b/jobs/54-cursor/log.txt on amdci2.julia.csail.mit.edu
Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: Cursor Agent <noreply@cursor.com>
Agent-Harness: Cursor Agent CLI
Agent-Model: auto
Agent-Session: ~/sandbox/goals/ci-green/work/cig-ouq-60-merge/log.txt (local transcript, amdci2)
@ChrisRackauckas
ChrisRackauckas marked this pull request as ready for review October 3, 2026 14:28
@ChrisRackauckas
ChrisRackauckas merged commit b9ebc3c into SciML:main Oct 3, 2026
24 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants