Skip to content

ltm: polarity analysis returns Unknown for all array reducers #480

Description

@bpowers

Summary

analyze_expr_polarity_with_context in src/simlin-engine/src/ltm.rs only handles the scalar two-arg forms Max(a, Some(b)) and Min(a, Some(b)). Every array reducer (Sum, Mean, Max(_, None), Min(_, None), Stddev, Rank) falls through the catch-all Expr2::App(_, _, _) => LinkPolarity::Unknown arm. Any variable computed via SUM(x[*]) or MEAN(x[*]) therefore contributes Unknown polarity, and every loop crossing such a node is classified Undetermined.

Why this matters

For Sum and Mean, polarity is trivially the argument's polarity (monotone in every element), so an entire class of arrayed feedback loops is misclassified as undetermined when their polarity is in fact recoverable.

Locations

  • src/simlin-engine/src/ltm.rs:2042-2075 -- the polarity analyzer with the catch-all Unknown
  • src/simlin-engine/src/ltm.rs:2341 -- strict GF monotonicity epsilon (EPSILON = 1e-10) flags numeric import noise as Unknown

Suggested fix

  • Add explicit cases in the polarity match: pass through the argument's polarity for Sum and Mean; return Unknown for Stddev and Rank (which have no monotone polarity).
  • For array Max(_, None) / Min(_, None), return the argument's polarity (max/min of a monotone family is monotone).
  • Consider a plateau-tolerant GF monotonicity check that ignores noise below a configurable epsilon rather than the strict 1e-10.

Severity

medium

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    engineIssues with the rust-based simulation engineltmLoops that Matter (LTM) analysis subsystem

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions