Repository navigation
Promote two agreeing one-sided limits over the reals (#719, step 2; #596) - #756
Merged
Merged
Conversation
) A two-sided limit is the two one-sided ones agreeing, and AngouriMath could not say so. The branch that compares them compares two `ComputeLimitDivideEtImpera` results -- the bare descent -- where a caller who names a side gets that descent *and* everything behind it: SolveAsIndeterminatePower, l'Hopital's rule, and the substitution that moves a finite destination out to infinity. The promotion could not be made before because the sides did not stay inside the reals. Over the complex plane `lim x->0- x^x` answers 1 from the continuation, so promoting agreement would give `lim x->0 x^x` the value 1 -- and `x^x` is not real to the left of 0 at all. #755 gave limits a codomain to read; this uses it, and **only under `Domain.Real`**, which is exactly what makes it sound: there that side has no value to agree with, so the case this could get wrong is the case that no longer arises. The expression #596 reported, at 0, over the reals: 1/ln(x + sqrt(x^2+1)) - 1/ln(x+1) left -1/2 already right -1/2 already both unevaluated -> -1/2 What must not be promoted, and is not: x * ln(x), x^x, sqrt(x), ln(x) real on one side only, so unevaluated 1/x, abs(x)/x, e^(1/x), arctan(1/x) sides disagree, so still NaN A second change came with it, and it belongs here rather than in #755 because this is what exposed it. A **two-sided** limit is now withdrawn if *either* approach leaves the reals, where the check asked about one direction only. `lim x->0 sqrt(x)` answered 0 while its own left-hand limit had been withdrawn, which is the two halves disagreeing about the same reading. Asked only where the answer would otherwise be NaN or nothing, so no limit that already answers pays for it, and bounded by a depth of two: each side may reach a two-sided limit of a subexpression, and without a bound the two questions branch into four and so on down the tree. Nothing changes by default. The complex reading answers as it always has, which is what keeps `LimitTest.TestNoLimit` meaning what it meant, and that is pinned. Suite 5135 -> 5147 passed / 0 failed, F# 130/130, corpus 112/117 with every verdict and answer byte-identical, rootcheck 596/596, propcheck 0 failures. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Step 2 of #719, on top of #755. Closes #596's reported expression.
What was wrong
A two-sided limit is the two one-sided ones agreeing, and AngouriMath could not say so. The branch that compares them compares two
ComputeLimitDivideEtImperaresults — the bare descent — where a caller who names a side gets that descent and everything behind it:SolveAsIndeterminatePower, l'Hôpital's rule, and the substitution that moves a finite destination out to infinity.The promotion could not be made before, and #719 says exactly why: the sides did not stay inside the reals. Over the complex plane
lim x->0- x^xanswers 1 from the continuation, so promoting agreement would givelim x->0 x^xthe value 1 — andx^xis not real to the left of 0 at all.LimitTest.TestNoLimitpins it as non-existent.#755 gave limits a codomain to read. This uses it.
What it does
Only under
Domain.Real, and that is exactly what makes it sound: there the offending side has no value to agree with, so the case this could get wrong is the case that no longer arises.The expression #596 reported, at 0, over the reals:
What must not be promoted, and is not:
x * ln(x),x ^ x,sqrt(x),ln(x)1/x,abs(x)/x,e^(1/x),arctan(1/x)NaNA second change, which this exposed
A two-sided limit is now withdrawn if either approach leaves the reals, where the check added in #755 asked about one direction only.
lim x->0 sqrt(x)answered0while its own left-hand limit had been withdrawn — the two halves disagreeing about the same reading. It belongs in this PR rather than #755 because promoting from the sides is what made the inconsistency visible.Cost
Asked only where the answer would otherwise be
NaNor nothing, so no limit that already answers pays for it. Bounded at a depth of two: each side may itself reach a two-sided limit of a subexpression, and without a bound the two questions branch into four and so on down the tree.Measured
work/rootcheck596/596 clean,work/propcheck0 failures.Nothing changes by default. The complex reading answers as it always has — pinned by tests, including that
x^xandx*ln(x)at 0 are still the definiteNaNthey were.🤖 Generated with Claude Code