Repository navigation
Report growth exactness and make factorial exact by Stirling - #1221
Conversation
…tirling Growth::relation() returns ParameterRelation::Exact when the Big-O form is also a lower bound (Theta) and UpperBound when any step widened it. factorial(x) of an exact single monomial now uses x^(x+1/2) e^(-x). A lower-bound property harness with a seeded negative control checks every exact claim numerically; four Stirling cases join the SymPy oracle. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agentic Review ReportPR #1221: Structural
Soundness probing (Exact must mean Θ, i.e. also a lower bound)I probed about 40 expressions through
The Quality
Feature test
FindingsCritical
Important
Minor
|
log_term dropped negative-weight atoms, so log(exp(-n)) = -n got growth O(1): a signed bound, not a magnitude bound. That made the dominance rule in add report n + log(exp(-n)) + 1 as exact O(n), and log(exp(-n))^2 as O(1). Every atom now contributes regardless of sign. Also adds signed shapes to the property generator and checks that exact registered complexities stay exact on round trip. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Review follow-up (0b41f6b):
|
GiggleLiu
left a comment
There was a problem hiding this comment.
Agentic Review Report
PR #1221. Reviewed head 0b41f6beba60c06db704ecf4200017f789ab8b1f against own base 2dc824e3da8f2c8b12103106206a2eed25ef6f2a (feat/growth-polynomial-exponents). Read-only review; no tracked edits, pushes, PR comments or merges.
Verdict
HOLD. The existing follow-up fixes the originally reported negative-log example, but a new exactness counterexample still returns a false Θ bound at the reviewed head.
Structural
Reviewed the four-file own-base diff and full growth-transfer logic. Stirling is sound for the supported exact positive single-monomial factorial arguments. Exactness propagation through ordinary positive sums/products and exact exponential polynomial expansions is reasonable. The covers rule is sound only if every widened summand has a true magnitude bound; log_growth still violates that invariant when its argument's growth is inexact.
Quality
The revised tests cover direct log(exp(-n)) and subtraction of smaller terms, but not algebraically cancelling polynomial terms inside a logarithm. Numeric f64 sampling is particularly weak here because the positive residual can disappear through catastrophic cancellation before the exponential underflows. Use symbolic simplification/limits or targeted identities for this class, not larger random sample counts.
Feature test
An independent standalone Rust probe compiled the exact #1220 and #1221 growth sources side by side using the shared expression code. Output is in /tmp/problemreductions-pr-review-20261029/growth-probe.txt; source in /tmp/problemreductions-growth-probe. The existing regression log(exp(-n))^2 now correctly produces O(n^2), UpperBound. Stirling for factorial(n) produces O(n^(0.5+n)*exp(-n)), Exact. The two counterexamples below remain broken. git diff --check BASE...HEAD passed. No full exact-head library/CLI suite was independently rerun.
Findings
- Critical:
log_growthon a widened argument produces a false magnitude bound, thenaddupgrades it to Exact.src/growth.rs:1208-1213and:1151-1159.
Let A(n)=n(n+1)−n²−n+exp(−n). Algebraically A(n)=exp(−n)>0 for all n. The production Expr does not expand the cancelling product, so Growth first widens A to O(n²). Applying log_growth yields O(log n), which is not a magnitude upper bound for log A=−n.
Actual independent outputs:
| Input | True value | Reported at 0b41f6b |
|---|---|---|
log(n*(n+1) - n^2 - n + exp(-n))^2 |
n² | O(log(n)^2), UpperBound |
n + log(n*(n+1) - n^2 - n + exp(-n)) + 1 |
1 | O(n), Exact |
Both complete expressions meet the stated nonnegative/nondecreasing trust contract. This is not merely a loose bound or unsupported domain. The second result falsely promises a lower bound and can make downstream comparisons assert a strict separation that does not exist.
Fix the operation at its source: a magnitude upper bound for A alone is insufficient to bound |log A|. Carry a proved positive lower bound/away-from-zero property, use appropriate exact symbolic reduction, or return Unknown where neither is available. Do not let covers consume a signed-only or otherwise uncertified logarithmic estimate. Add these identities as targeted regression tests. Merely marking the logarithm UpperBound is insufficient because the first result is not an upper bound at all.
GitHub PR policy audit
GATE: PASS. This is the harm-signals gate only; it does not override the correctness verdict above.
- harm.secrets (
security.no-secrets): OK. No obvious credential/private-key/token addition detected in the own-base diff. - harm.dangerous-files (
git.harm-signals): OK. No conflict markers, unexplained archives or local scratch/config artifacts detected. - harm.generated-artifacts (
code.generated-artifacts): OK. No blacklisted generated graph/schema/example exports or build targets added. Test oracle fixtures are intentional test inputs; small browser contracts/fonts are intentional source assets. - harm.cache (
code.generated-cache): OK. No cache directories added. - harm.debug-leftovers (
code.debug-leftovers): OK. No debugger, breakpoint or temporary debug print addition detected. Browser performance marks are deliberate verification instrumentation. - pr.description-quality (
github.pr-description-quality): OK. Purpose, changes, validation and limitations are described. - pr.traceable (
github.prs-traceable): OK. The PR states its purpose and own stack context.
Policy evidence: own-base name/status, numstat and patch inspection; added-line secret/conflict/debug scan; git diff --check; gh-axi pr view 1221 --full --comments --reviews. No claim of exhaustive secret scanning. The parent reviewer owns the final head/base recheck before any merge.
Stacked on #1220.
What
Growth::relation()now says whether a computed Big-O form is tight:ParameterRelation::Exact: the expression is Θ(growth), so the growth is also a lower bound.ParameterRelation::UpperBound: some step widened the expression.None: the growth is unknown.This reuses the
ParameterRelationtype that reduction overheads already use.The rules for exactness:
n - 1andn^2 - n log nare exact, whilen - mandn*m - n^2are upper bounds.(2n)^n, now counts as exact.ln ln vthat was widened toln vis not exact.factorial(x)of an exact single monomial now uses Stirling's formula,x! ≍ x^(x+1/2) e^(-x), and is exact. Before, it was bounded byx^x. Any other factorial argument still widens tox^xand is reported as an upper bound.Why
The complexity consistency audit (#1219) can now report a violation as proven only when the registered side's growth is exact. With an upper-bound growth, "registered ≻ derived" might only show that our bound is loose. Stirling also makes
factorial(n)strictly smaller thann^n, which the comparison could not separate before.Visible change: factorial complexities now display as, for example,
O(n^(0.5 + n) * exp(-1 * n))instead ofO(n^n).Tests
test_growth_relation: 15 exact cases, 13 upper-bound cases, and one unknown case.test_growth_factorial_stirling: equalities and strict orderings aroundn!.growth ≤ C·e. Its negative control seeds a bug: anAddthat returns the product of its summands and calls it exact. The harness catches it. The harness uses variable-only leaves, because constant leaves can keep an exact term hidden past the finite window it evaluates.ratio_limit√(2π) and 2√π for the equivalences), and all of them agree.cargo test --workspacepasses. Clippy reports only the existingnormalized_nwarning.🤖 Generated with Claude Code