Skip to content

Symbolics 7 compatibility breaks extension loading and OUQ variable discovery #41

Description

@ChrisRackauckas-Claude

Summary

main at 246141f8f176de2ad712709486533c84f03b3e5a is not compatible with the Symbolics 7 / SymbolicUtils 4 versions admitted by #40. There are two independent stages:

  1. CanonicalMoments.SymbolicsExt cannot precompile because it imports the removed, non-public Symbolics.array_term, and its @register_array_symbolic signature uses the AbstractVecOrMat union that Symbolics 7's wrapper expansion cannot process.
  2. After a public-API-only prototype clears precompilation and the OUQ operator promotion ambiguity, SymbolicUtils 4's documented operator-boundary behavior makes get_variables(𝔼(Q)) return 𝔼(Q) instead of Q. OUQBase then cannot associate constraints with random-variable groups.

This therefore needs a broader Symbolics 7 migration, including a deliberate variable-discovery design for OUQ operators, rather than only a one-line compatibility fix.

CI and dependency boundary

The failures began at merge commit 246141f8, PR #40, which added Symbolics 7.30 and SymbolicUtils 4.38 compatibility. The initial push failures are visible in:

The Julia 1 job resolved Julia 1.12.6, Symbolics 7.31.0, and SymbolicUtils 4.39.0. A clean local reproduction on current compatible releases resolved Symbolics 7.32.0 / SymbolicUtils 4.40.0 and failed identically, so this is still current.

Symbolics.array_term existed in Symbolics 6.39.1 as an unexported/non-public helper. It was removed by Symbolics commit 7b59796, with v7.0.0 the first tag containing the removal. Thus the source boundary is Symbolics 6 to 7, not specifically 7.31.

Stage 1: extension and operator construction failures

On clean main:

timeout 3600 env JULIA_DEPOT_PATH="$PWD/.julia-depot" GROUP=Core \
  julia +1.12 --project=. -e '
    import Pkg
    Pkg.test(; coverage=false,
      julia_args=["--check-bounds=auto", "--compiled-modules=yes", "--depwarn=yes"],
      force_latest_compatible_version=false,
      allow_reresolve=true)
  '

The extension reports:

WARNING: Imported binding Symbolics.array_term was undeclared at import time
ERROR: FieldError: type Union has no field `parameters`
...
Symbolics/src/wrapper-types.jl:160
Symbolics/src/register.jl:149
lib/CanonicalMoments/ext/SymbolicsExt.jl:1

The Union is the AbstractVecOrMat registration. Splitting it into vector and matrix registrations is not sufficient: @register_array_symbolic generates overlapping scalar-symbolic wrapper methods for the two registrations, which is forbidden during precompilation.

OUQBase also defines broad downstream methods such as:

SymbolicUtils.promote_symtype(::𝔼_, x) = x

These are ambiguous with SymbolicUtils 4's promote_symtype(::Operator, ::Type{T}) method. The LTS/pre jobs report:

MethodError: promote_symtype(::OUQBase.𝔼_, ::Type{Real}) is ambiguous

Public-API prototype that cleared stage 1

A local prototype used only bindings verified public through their owning modules:

  • Symbolics.wrap
  • SymbolicUtils.unwrap, SymbolicUtils.term, and SymbolicUtils.symtype

SymbolicUtils.shape is not public through its owning module and was not used. The prototype:

  • replaced array_term with SymbolicUtils.term(...; type=AbstractMatrix{Real}, shape=axes(companion)), followed by Symbolics.wrap;
  • registered the two-argument eigvec operation once on AbstractArray{<:Real} with a symtype-based 1-D/2-D guard, preserving vector and matrix behavior and rejecting a 3-D symbolic array;
  • declared SymbolicUtils as a weak dependency/extension trigger;
  • constructed 𝔼 and with exported SymbolicUtils.term(...; type=symtype(x)) and removed the ambiguous downstream promote_symtype methods.

Focused tests covered concrete symbolic shapes, numeric build_function equivalence for the companion matrix, eigvals, eigvecs with a vector of eigenvalues, generalized eigvecs with a matrix metric, and 3-D rejection. The actual grouped harness passed:

Symbolics extension | 11  11  35.3s
Testing CanonicalMoments tests passed

This proves a public construction route exists, but it exposes stage 2.

Stage 2: OUQ variable discovery stops at operators

With the public prototype applied, this Julia 1.10 command cleared extension precompilation and the previous promotion ambiguity:

timeout 3600 env JULIA_DEPOT_PATH="$PWD/.julia-depot" GROUP=OUQBase \
  julia +1.10 --project=. -e '
    import Pkg
    Pkg.develop([Pkg.PackageSpec(path=joinpath("lib", name))
      for name in readdir("lib") if isdir(joinpath("lib", name))])
    Pkg.test(; coverage=false,
      julia_args=["--check-bounds=auto", "--compiled-modules=yes", "--depwarn=yes"],
      force_latest_compatible_version=false,
      allow_reresolve=true)
  '

The focused operator test passed 2/2. The existing Flood Problem (Q only) test then failed:

ArgumentError: A random variable can only belong to one random variable group
  get_group_name(...)
  create_constraints_map(...)

The immediate behavior is:

constraints = [𝔼(Q) ~ 1320.42]
Symbolics.get_variables(only(constraints))
# Set(Any[𝔼_()(Q)])

The admissible-set map contains Q, so 𝔼(Q) cannot match it. SymbolicUtils 4's default_is_atomic intentionally treats Terms whose operation is an Operator as atomic. OUQBase variable discovery therefore needs a package-specific, public-API traversal or preprocessing step that deliberately crosses 𝔼/ boundaries while preserving the intended behavior for other symbolic operators.

Scope/status

No test was skipped, silenced, weakened, or loosened during this investigation. The public prototype was reverted after the full OUQBase group exposed stage 2; no patch or dependency pin was retained.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions