Skip to content

Symbolics NaNMath.pow lowering variants break builder sanitizers #4132

@finmod

Description

@finmod

mtk_issue_bundle.zip

Title: Symbolics codegen emits varied NaNMath.pow lowered forms that escape sanitizers and break compiled builder functions

Summary

When generating numeric builder functions, Symbolics/ModelingToolkit sometimes lowers fractional powers (x^α) into varied textual/AST variants that reference NaNMath.pow in dotted/wrapped/parenthesized shapes. These shapes escape robust string/AST sanitizers in our initialization pipeline and survive into the final lowered/compiled residuals, causing runtime MethodError when the compiled builders run.

Environment

  • OS: Windows
  • Repo: DyadDemos MacroeconomicModelDemo (local)
  • Julia project: --project=., attached Project.toml/Manifest.toml in repo root
  • Files attached: failed_builder_exprs.log, init_solver_clean.jl, check_consistency.jl, run_cell14.jl, and a zipped bundle of these files

Reproduction (minimal steps)

  1. Clone the attached repo (or use provided bundle).
  2. From project root run:
julia --project=. check_consistency.jl
  1. Observe runtime builder lowering printed in generated/failed_builder_exprs.log and MethodError during compiled residual smoke-test.

Representative failing lowered node forms (observed in logs)

  • (NaNMath.pow)(ˍ₋arg1[40], 0.6)
  • (NaNMath.pow)((+)(1.0e-8, (abs)(ˍ₋arg1[40])), 0.6)
  • (NaNMath.pow)((+)(ˍ₋arg1[63], (*)(-1, ˍ₋arg1[48])), 0.5)
  • (NaNMath.pow)((/)((+)(1, ˍ₋arg1[59]), (+)(1, ˍ₋arg1[63])), 2.0)

What I tried locally

  • Implemented multi-stage sanitizers in src/init_solver_clean.jl (string-level guarded replacers, regex normalizers, AST walker, deterministic prewalk, placeholder-based textual→parse→AST fallback).
  • Added _safe_pow and a Main.NaNMath shim so lowered NaNMath.pow resolves to a safe fallback.
  • Despite these, lowered builder outputs still include NaNMath.pow in the shapes above and cause a runtime MethodError in the smoke test.

Suspected cause / pointers

  • Codegen lowering for fractional power ^ appears to emit multiple non-canonical call forms (parenthesized/dotted/wrapped), which make downstream sanitizers fragile.
  • Suggest making the lowering canonical (consistent Expr form) or exposing a hook so downstream code can reliably canonicalize pow lowering.

Attachments

  • failed_builder_exprs.log (full run output showing lowered builder functions)
  • init_solver_clean.jl (our sanitizer + shim implementations)
  • check_consistency.jl (driver to reproduce)
  • run_cell14.jl (short script used to reproduce notebook cell warnings)
  • zipped archive: mtk_issue_bundle.zip

Notes

  • I can prepare a smaller minimal reproduction if the maintainers prefer a reduced example. I am available to iterate on narrow testcases or propose a small patch to canonicalize lowering.

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