Background
big_o_normal_form (src/big_o.rs) currently answers Big-O queries by fully expanding expressions via canonical_form (src/canonical.rs, 431 lines) and then discarding almost everything it computed. This exponential-cost pipeline was the root cause of issue #1069; a stopgap cap (MAX_CANONICAL_TERMS = 50_000) prevents the OOM but makes the pipeline refuse on large inputs, and its dominance step uses a foolable two-point numerical sampling heuristic. The growth domain (#1075) computes the same answers bottom-up at linear cost.
Full design (shared overview for this batch): docs/design/symbolic-growth-domain.md, section M2.
Objective
Swap big_o_normal_form's implementation to the growth domain, then delete the expansion machinery: canonical.rs (including the stopgap cap), the asymptotic_normal_form compatibility wrapper, and the pred-sym subcommand that exposed it. One trusted asymptotic engine remains.
Interface (Input → Output)
pub fn big_o_normal_form(&Expr) -> Result<Expr, AsymptoticAnalysisError> — signature unchanged; internally Growth::from_expr → render back to a display Expr; Growth::Unknown maps to the existing Unsupported error. CLI callers (big_o_of, overhead_to_json, format_path_text) compile untouched.
canonical_form, asymptotic_normal_form, and their lib.rs re-exports: deleted (internal API breakage is in-scope per the design).
pred-sym CLI: canon subcommand deleted (no live consumers — the find-problem skills use only big-o and eval); compare narrows to Big-O equivalence via the growth domain.
src/rules/analysis.rs:227 (prepare_expr_for_comparison): stop calling canonical_form (return the expr clone; the full analysis rewire is a separate issue in this milestone).
Technical recommendations (non-binding)
- Render
Growth → Expr deterministically (sorted terms) so Display output is platform-stable.
- Rewrite the affected unit tests:
src/unit_tests/big_o.rs keeps its behavioral cases (they should pass unchanged where inputs are in-domain); src/unit_tests/expr.rs's asymptotic_normal_form tests move to growth semantics or are deleted with the wrapper; problemreductions-cli/tests/pred_sym_tests.rs drops canon cases.
- Update the two find-problem skill docs only if their documented
pred-sym big-o examples change behavior (linear-exponent inputs should not).
Verification
cargo test is green and grep -rn "canonical_form" src/ problemreductions-cli/ returns nothing — the combination proves the pipeline was rewired, not renamed.
- Behavioral spot checks (run exactly):
pred-sym big-o "3*n^2 + 5*n + 7" prints O(n^2).
pred-sym big-o "1.5^num_subsets * num_subsets^2" prints an exponential-times-polynomial bound (e.g. O(1.5^num_subsets * num_subsets^2) or its base-2-normalized rendering) — this is the find-problem skills' live input shape, which must keep working.
pred-sym big-o "(n + m)^2 * (n + m)^2" prints a degree-4 bound (e.g. O(n^4 + n^3*m + n^2*m^2 + n*m^3 + m^4)), instantly.
Negative control: pred-sym big-o "factorial(n)" exits non-zero with an unsupported/unknown message (no fake bound), and pred-sym canon "n" fails as an unknown subcommand — proving unsupported content is refused loudly rather than bluffed.
Dependencies
Depends on #1075. Milestone: Symbolic Growth Domain & Pareto Search.
Out of scope
The CLI O(<raw expr>) fallback deletion, #1069 regression tests, and --json rendering fix (next issue); the full analysis.rs machinery deletion (separate issue in this milestone).
Background
big_o_normal_form(src/big_o.rs) currently answers Big-O queries by fully expanding expressions viacanonical_form(src/canonical.rs, 431 lines) and then discarding almost everything it computed. This exponential-cost pipeline was the root cause of issue #1069; a stopgap cap (MAX_CANONICAL_TERMS = 50_000) prevents the OOM but makes the pipeline refuse on large inputs, and its dominance step uses a foolable two-point numerical sampling heuristic. The growth domain (#1075) computes the same answers bottom-up at linear cost.Full design (shared overview for this batch):
docs/design/symbolic-growth-domain.md, section M2.Objective
Swap
big_o_normal_form's implementation to the growth domain, then delete the expansion machinery:canonical.rs(including the stopgap cap), theasymptotic_normal_formcompatibility wrapper, and thepred-symsubcommand that exposed it. One trusted asymptotic engine remains.Interface (Input → Output)
pub fn big_o_normal_form(&Expr) -> Result<Expr, AsymptoticAnalysisError>— signature unchanged; internallyGrowth::from_expr→ render back to a displayExpr;Growth::Unknownmaps to the existingUnsupportederror. CLI callers (big_o_of,overhead_to_json,format_path_text) compile untouched.canonical_form,asymptotic_normal_form, and theirlib.rsre-exports: deleted (internal API breakage is in-scope per the design).pred-symCLI:canonsubcommand deleted (no live consumers — the find-problem skills use onlybig-oandeval);comparenarrows to Big-O equivalence via the growth domain.src/rules/analysis.rs:227(prepare_expr_for_comparison): stop callingcanonical_form(return the expr clone; the full analysis rewire is a separate issue in this milestone).Technical recommendations (non-binding)
Growth → Exprdeterministically (sorted terms) soDisplayoutput is platform-stable.src/unit_tests/big_o.rskeeps its behavioral cases (they should pass unchanged where inputs are in-domain);src/unit_tests/expr.rs'sasymptotic_normal_formtests move to growth semantics or are deleted with the wrapper;problemreductions-cli/tests/pred_sym_tests.rsdropscanoncases.pred-sym big-oexamples change behavior (linear-exponent inputs should not).Verification
cargo testis green andgrep -rn "canonical_form" src/ problemreductions-cli/returns nothing — the combination proves the pipeline was rewired, not renamed.pred-sym big-o "3*n^2 + 5*n + 7"printsO(n^2).pred-sym big-o "1.5^num_subsets * num_subsets^2"prints an exponential-times-polynomial bound (e.g.O(1.5^num_subsets * num_subsets^2)or its base-2-normalized rendering) — this is the find-problem skills' live input shape, which must keep working.pred-sym big-o "(n + m)^2 * (n + m)^2"prints a degree-4 bound (e.g.O(n^4 + n^3*m + n^2*m^2 + n*m^3 + m^4)), instantly.Negative control:
pred-sym big-o "factorial(n)"exits non-zero with an unsupported/unknown message (no fake bound), andpred-sym canon "n"fails as an unknown subcommand — proving unsupported content is refused loudly rather than bluffed.Dependencies
Depends on #1075. Milestone: Symbolic Growth Domain & Pareto Search.
Out of scope
The CLI
O(<raw expr>)fallback deletion, #1069 regression tests, and--jsonrendering fix (next issue); the fullanalysis.rsmachinery deletion (separate issue in this milestone).