Skip to content

Fix complex boundary condition splitting (supersedes #133) - #161

Merged
ChrisRackauckas merged 24 commits into
SciML:masterfrom
xtalax-droid:forge/supersede-133
Oct 29, 2026
Merged

ChrisRackauckas merged 24 commits into
SciML:masterfrom
xtalax-droid:forge/supersede-133

Conversation

@xtalax-droid

Copy link
Copy Markdown
Contributor

Supersedes #133 (this branch merges its 22 commits with authorship intact; thanks to its author); it is rebased by merge onto current master and reconciled with #137.

🤖 AI-generated pull request. The code was written by AI agents: Codex CLI 0.156–0.157 (gpt-6-luna, gpt-6-sol), Devin CLI 3000.11 (swe-2-max) and Claude Code 2.1.301 (claude-opus-5-5). Each agent commit's trailers name its harness and model. Three early commits (abb3048, 0b76a1d, a9b0189) carry no agent trailers, and 0057ebc is a merge of master. So far the PR has been reviewed only by AI agents (Claude Code / claude-opus-5-5 and Codex CLI / gpt-6.1-sol); no human has reviewed it.

The merge and conflict-resolution commit on this branch is by Claude Code 2.1.312 (claude-sonnet-5-5), unreviewed; its Agent-* trailers say so.

Part of #127. The behaviour is that of #133 (see its description for the full rules, examples and review history); this description covers what differs.

What changed relative to #133

Breaking change

This changes the public behaviour of handle_complex, and with it symbolic_discretize: boundary inputs that master accepted now throw ArgumentError (for example untyped [ψ(t,0) ~ 0, Dx(ψ(t,0)) ~ 0] and [0 ~ ψ(t,0), Dx(ψ(t,0)) ~ 0] on a complex system, and [0 ~ sin(t), 0 ~ cos(t)]). They reach PDEBase as the same equations as untyped Robin conditions with an imaginary coefficient, which master silently turns into clamped conditions; see #133's description for the full table. It requires a minor version bump to 0.2.0 (0.x SemVer) before merging, together with compat updates in MethodOfLines, NeuralPDE and PDESystemLibrary. Project.toml is deliberately unchanged here (0.1.41) because the bump is the maintainers' call. This PR must not be merged or registered as a 0.1.x release.

Known limitations

  • An untyped field is read by shape. Declaring ψ(..)::Complex is the reliable path, and typed fields split exactly.
  • On a system with no complex values, an untyped im*Dx(ψ(t,1)) ~ ψ(t,1) pre-splits to [0 ~ ψ(t,1), Dx(ψ(t,1)) ~ 0] and is read as a real grouping. That is wrong, and it is the same as master. ψ(t,0) + im*Dx(ψ(t,0)) ~ 0 behaves the same way. docs/src/workflow.md tells users to declare ::Complex for such conditions.
  • Symbolics truncates numeric complex literals on untyped fields before PDEBase sees them (documented in workflow.md).
  • The Symbolics.SplitComplexEquation marker path (Add opt-in split_complex_equation returning a marked SplitComplexEquation JuliaSymbolics/Symbolics.jl#2008) is valid only for holomorphic conditions, and is untested here because no registered Symbolics defines it.
  • Not verified: downstream MethodOfLines, PDESystemLibrary and NeuralPDE suites, no end-to-end MethodOfLines Robin solve, Julia pre, and the full Downgrade resolution.

Tests

On this branch (head after the merge), with Symbolics at the registry resolution of each channel:

  • test/complex_boundary_conditions.jl, test/complex_splitting.jl, test/d_orders.jl through TestEnv on Julia 1.12.1 (default) and 1.10.12 (+lts): 62/62, 4+6+1+24 (all complex_splitting testsets, 35 total), and 15/15 on both channels.
  • GROUP=Core on 1.12.1: all files pass; complex_boundary_conditions.jl 62/62, complex_splitting.jl 35/35, d_orders.jl 15/15, to_box_bcs.jl 1412/1412; the only broken entries are 7 pre-existing @test_broken in boundary_syntax.jl (96 pass, 7 broken, 103 total).
  • GROUP=Core on 1.13.2 (+release): the same counts.
  • GROUP=QA on 1.12.1: QA/qa.jl 20/20.
  • Runic --check on src/make_pdesys_compatible.jl, src/variable_map.jl, test/complex_boundary_conditions.jl and test/complex_splitting.jl: clean.

🤖 Posted by an AI agent · harness: Claude Code 2.1.312 · model: claude-sonnet-5-5
Review: unreviewed
Session: a20a681b-e8cc-4c82-a40d-a5b8349014e2

ChrisRackauckas and others added 24 commits September 23, 2026 00:12
Test complex coefficients, products between dependent fields, and duplicated real/imaginary boundary equations. The regression fails against the current normalization before the fix.

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: Codex <noreply@openai.com>
Agent-Harness: Codex CLI 0.156.0
Agent-Model: gpt-6-luna
Agent-Session: local session, transcript at /home/crackauc/sandbox/agent-jobs/PDEBase.jl/jobs/125-codex/log.txt on amdci2.julia.csail.mit.edu
Retain ModelingToolkit's equation-pair grouping, reconstruct each complex residual, substitute real and imaginary dependent variables, then expand derivatives and complex products before splitting. Generate real-valued component variables and use the same residual split for complex boundary equations.

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: Codex <noreply@openai.com>
Agent-Harness: Codex CLI 0.156.0
Agent-Model: gpt-6-luna
Agent-Session: local session, transcript at /home/crackauc/sandbox/agent-jobs/PDEBase.jl/jobs/125-codex/log.txt on amdci2.julia.csail.mit.edu
Split each side of complex equations independently so downstream symbolic consumers retain the equation form they expect.

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>

Co-Authored-By: Codex <noreply@openai.com>

Agent-Harness: Codex CLI 0.156.0

Agent-Model: gpt-6-luna

Agent-Session: local session, transcript at /home/crackauc/sandbox/agent-jobs/PDEBase.jl/jobs/125-codex/log.txt on amdci2.julia.csail.mit.edu
Cover a time-dependent complex Dirichlet condition at the BC splitting boundary, rename the imaginary component local, and remove the unused ComplexEq type. Keep handle_complex's real-equation branch because complex BC-only systems can reach it.

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>

Co-Authored-By: Codex <noreply@openai.com>

Agent-Harness: Codex CLI 0.156.0

Agent-Model: gpt-6-luna

Agent-Session: local session, transcript at /home/crackauc/sandbox/agent-jobs/PDEBase.jl/jobs/125-codex/log.txt on amdci2.julia.csail.mit.edu
Resolve the follow-up against the now-merged complex coupling change and current release base.

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>

Co-Authored-By: Codex <noreply@openai.com>

Agent-Harness: Codex CLI 0.156.0

Agent-Model: gpt-6-luna

Agent-Session: local session, transcript at /home/crackauc/sandbox/agent-jobs/PDEBase.jl/jobs/125-codex/log.txt on amdci2.julia.csail.mit.edu
Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: Codex <noreply@openai.com>
Agent-Harness: Codex CLI 0.156.1
Agent-Model: gpt-6-sol
Agent-Session: local session, transcript at /home/crackauc/sandbox/agent-jobs/PDEBase.jl/jobs/130-codex/log.txt on amdci2.julia.csail.mit.edu
Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: Codex <noreply@openai.com>
Agent-Harness: Codex CLI 0.156.1
Agent-Model: gpt-6-sol
Agent-Session: local session, transcript at /home/crackauc/sandbox/agent-jobs/PDEBase.jl/jobs/130-codex/log.txt on amdci2.julia.csail.mit.edu
Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: Codex <noreply@openai.com>
Agent-Harness: Codex CLI 0.156.1
Agent-Model: gpt-6-luna
Agent-Session: local session, transcript at /home/crackauc/sandbox/agent-jobs/PDEBase.jl/jobs/127-codex/log.txt on amdci2.julia.csail.mit.edu
Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: Codex <noreply@openai.com>
Agent-Harness: Codex CLI 0.156.1
Agent-Model: gpt-6-luna
Agent-Session: local session, transcript at /home/crackauc/sandbox/agent-jobs/PDEBase.jl/jobs/127-codex/log.txt on amdci2.julia.csail.mit.edu
Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: Codex <noreply@openai.com>
Agent-Harness: Codex CLI 0.156.1
Agent-Model: gpt-6-sol
Agent-Session: local session, transcript at /home/crackauc/sandbox/agent-jobs/PDEBase.jl/jobs/130-codex/log.txt on amdci2.julia.csail.mit.edu
Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: Codex <noreply@openai.com>
Agent-Harness: Codex CLI 0.156.1
Agent-Model: gpt-6-luna
Agent-Session: local session, transcript at /home/crackauc/sandbox/agent-jobs/PDEBase.jl/jobs/127-codex/log.txt on amdci2.julia.csail.mit.edu
Flatten nested boundary groups without inferring complex equations from their shape. Use typed complex fields for Symbolics pre-split complex boundary expressions, split known complex equations mathematically, and reject false boundary sides.

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: Codex <noreply@openai.com>
Agent-Harness: Codex CLI 0.156.1
Agent-Model: gpt-6-luna
Agent-Session: local session, transcript at /home/crackauc/sandbox/agent-jobs/PDEBase.jl/jobs/127-codex/log.txt on amdci2.julia.csail.mit.edu
Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: Codex <noreply@openai.com>
Agent-Harness: Codex CLI 0.156.1
Agent-Model: gpt-6-luna
Agent-Session: local session, transcript at /home/crackauc/sandbox/agent-jobs/PDEBase.jl/jobs/127-codex/log.txt on amdci2.julia.csail.mit.edu
Real systems that group boundary conditions per boundary point (clamped
beam, interface conditions) produce the same nested two-equation shape
Symbolics emits when it pre-splits a complex boundary condition, and were
rejected with advice to declare ::Complex. The pair rejection now only
runs when the equations or boundary conditions already contain complex
values, except for a `0 ~ expr` member over a parameter-only expression,
which constrains no unknown and is a definite pre-split signature.

The boundary `false` check is also skipped for Complex-typed fields,
where Symbolics' `real(ψ) ~ false, imag(ψ) ~ true` split of `ψ ~ im` is
exact, and the docs now name the silently truncated literal forms.

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: Devin <noreply@cognition.ai>
Agent-Harness: Devin CLI 3000.11.1
Agent-Model: swe-2-max
Agent-Session: local session, transcript at /home/crackauc/sandbox/agent-jobs/PDEBase.jl/jobs/127-codex/log-cont1.txt on amdci2.julia.csail.mit.edu
Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: Codex <noreply@openai.com>
Agent-Harness: Codex CLI 0.157.1
Agent-Model: gpt-6-luna
Agent-Session: local session, transcript at /home/crackauc/sandbox/aj/p127/log-cont2.txt on amdci2.julia.csail.mit.edu
Symbolics 7.42 marks an opted-in complex `~` as `SplitComplexEquation`
(split_complex_equation), which preserves the original complex equation.
handle_complex restores that original before flattening so the condition
splits with real and imaginary parts coupled; plain `~` output and
hand-written pairs stay ambiguous and are still rejected.

Nested pairs containing a literal `0 ~` member now reject
unconditionally: that is Symbolics' pre-split signature (the imaginary
half of a real-typed lhs) and otherwise flattens silently into wrong
real BCs for untyped complex conditions on real-coefficient PDEs. Real
grouped pairs of that shape must be passed un-nested.

Bump the Symbolics compat to 7.42 for the marker API, and document the
opt-in marker alongside the typed `::Complex` recommendation.

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: Devin <noreply@cognition.ai>
Agent-Harness: Devin CLI 3000.11.3
Agent-Model: swe-2-max
Agent-Session: local session, transcript at /home/crackauc/sandbox/aj/p127/log-cont3.txt on amdci2.julia.csail.mit.edu
A nested pair `[L ~ a, 0 ~ b]` where `L` is a single dependent-variable
application (possibly under a `Differential`) and neither `a` nor `b`
mentions a dependent variable can only be Symbolics' split of
`L(ψ) ~ a + i b`, so rebuild it as that equation instead of rejecting.
This restores MethodOfLines' "Schroedinger with complex bcs" test input,
which passed on master and errored on the previous head.

Pairs whose members both have a `0 ~` left-hand side mean the same thing
as a real grouping or a `0 ~` complex split, so they pass through; other
nested pairs containing a `0 ~` member keep being rejected, as do
same-instance pairs on systems with complex values.

Also document that `Symbolics.split_complex_equation` is only valid for
holomorphic conditions on untyped fields (`conj`/`real`/`imag`/`abs`/`abs2`
simplify before the marker is built) and that numeric complex data
truncates the same way as `~`; pin both limitations in tests. Remove the
dead `Symbolics.value` try/catch in `_split_complex_components` and bump
to 0.1.39 so the release can register.

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: Devin <noreply@cognition.ai>
Agent-Harness: Devin CLI 3000.11.3
Agent-Model: swe-2-max
Agent-Session: local session, transcript at /home/crackauc/sandbox/aj/p127/log-cont6.txt on amdci2.julia.csail.mit.edu
A nested pair of `0 ~`-lhs equations was passed through unconditionally,
but a pair where exactly one member is free of dependent variables is
the Symbolics pre-split of a residual-form complex condition like
`0 ~ ψ(t,0) - exp(im*t)` — as a real grouping a DV-free `0 ~ b`
constrains no unknown — and passing it through silently mis-splits it:
each member was duplicated into both components. Rebuild such a pair as
`0 ~ a + i b` so it splits with real and imaginary parts coupled; keep
the pass-through only when both members mention a dependent variable
(broadcast Neumann pairs, grouped real constraints) and reject pairs
with no dependent variable at all.

Docs: write complex conditions with the field on the left, since a
reversed `exp(im*t) ~ ψ(t,0)` pre-splits to a shape that cannot be
reconstructed. Drop the testset that pinned a Symbolics truncation
defect as PDEBase behaviour; the workflow doc sentence covers it.

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: Devin <noreply@cognition.ai>
Agent-Harness: Devin CLI 3000.11.3
Agent-Model: swe-2-max
Agent-Session: local session, transcript at /home/crackauc/sandbox/aj/p127/log-cont7.txt on amdci2.julia.csail.mit.edu
- Define the `SplitComplexEquation` restore method only when the installed
  Symbolics provides it, and set the Symbolics compat floor back to 7.39.2.
  Every registered Symbolics (up to 7.46.0) lacks the marker, so the
  previous `Symbolics = "7.42"` entry made PDEBase fail to precompile.
  The pre-split error message names `split_complex_equation` only when it
  exists, and the marker testset runs only when Symbolics provides it.
- Read pre-split pairs with the field on the right (`exp(im*t) ~ ψ(t, 0)`,
  `exp(im*t) ~ Dx(ψ(t, 1))`, `ψ(t, 0) - exp(im*t) ~ 0`) as the mirror image
  of the field-on-the-left rules. These previously split silently into
  inconsistent real systems.
- Handle array-valued dependent variables when collecting dependent
  operations in `handle_complex`; the "Optimization-system replaced
  variable map" test merged from master errored with a MethodError.
- Build the unsplit complex BC in complex_splitting.jl with the `Equation`
  constructor instead of the unreleased marker API.
- Bump version to 0.1.40 (0.1.39 is registered).

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Harness: Claude Code 2.1.301
Agent-Model: claude-opus-5-5
Agent-Session: local session ID 30f090ef-c4ec-41be-88b4-ad1ffd17da57 (headless claude -p, no URL)
A nested `[0 ~ a, L ~ b]` pair whose members both mention a dependent
variable, such as `[0 ~ u(t, 0), u(t, 1) ~ 1]` on a real heat equation, was
rejected with an ArgumentError although master accepted it and returned it
unchanged. Such pairs are now left to `_ambiguous_presplit_bc`, which rejects
them only when the system shows complex values, matching the existing rule
for same-point pairs. Pairs whose `0 ~` member or second member constrains
no unknown are still rejected.

On a purely real system an untyped `im*Dx(ψ(t, 1)) ~ ψ(t, 1)` pre-splits to
the same shape and is read as real, as on master; workflow.md says to
declare `::Complex` for such conditions.

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Harness: Claude Code 2.1.301
Agent-Model: claude-opus-5-5
Agent-Session: local session ID 30f090ef-c4ec-41be-88b4-ad1ffd17da57 (headless claude -p, no URL)
…rejected

On an untyped field `ψ(t, 0) + im*Dx(ψ(t, 0)) ~ 0` reaches PDEBase as
`[ψ(t, 0) ~ 0, Dx(ψ(t, 0)) ~ 0]`, and `im*Dx(ψ(t, 0)) ~ ψ(t, 0)` as
`[0 ~ ψ(t, 0), Dx(ψ(t, 0)) ~ 0]`, so these are indistinguishable from the
grouped clamped conditions that master accepted on complex systems. Master
turns the Robin conditions into clamped ones. The new testset asserts that
both forms and both groupings are rejected, and that the typed form splits
exactly. Removing the same-point check from `_ambiguous_presplit_bc` makes
two of its assertions fail; no other test covered that check.

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Harness: Claude Code 2.1.301
Agent-Model: claude-opus-5-5
Agent-Session: local session ID 30f090ef-c4ec-41be-88b4-ad1ffd17da57 (headless claude -p, no URL)
…ndition splitting

Merges the 22 commits of SciML/PDEBase#133 (branch agent/127-complex-bcs-master of
ChrisRackauckas-Claude/PDEBase.jl, head e4ec7f4) with their authorship intact, onto
current master. Conflicts: Project.toml keeps master's version; in
src/make_pdesys_compatible.jl split_complex_bc keeps master's SciML#137 form (no duplication
of real BC data into the imaginary component, Pairs split as equations) and drops the
PreSplitComplexBC branch and SciML#133's older hascomplex/duplicate path.

Agent-Harness: Claude Code 2.1.312
Agent-Model: claude-sonnet-5-5
Agent-Session: a20a681b-e8cc-4c82-a40d-a5b8349014e2
Agent-Review: unreviewed
Co-authored-by: Claude Code <agent@noreply.juliahub.com>
_dv_application looked through a single Differential layer, so a pre-split
mixed-derivative condition such as Dt(Dx(u(t, 0))) ~ exp(im*t) was rejected.
It now unwraps Differential applications recursively. Adds a mixed-derivative
regression test (field on the left and on the right).

Agent-Harness: Claude Code 2.1.312
Agent-Model: claude-sonnet-5-5
Agent-Session: a20a681b-e8cc-4c82-a40d-a5b8349014e2
Agent-Review: unreviewed
Co-authored-by: Claude Code <agent@noreply.juliahub.com>
@ChrisRackauckas
ChrisRackauckas marked this pull request as ready for review October 29, 2026 01:53
@ChrisRackauckas
ChrisRackauckas merged commit dc3ebd7 into SciML:master Oct 29, 2026
27 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.

3 participants