Skip to content

The reading is a parameter of the domain question, not a property of the expression (#721) - #1090

Merged
Rafael-SOWNet merged 1 commit into
masterfrom
feat/domain-condition-in-a-reading
Aug 27, 2026
Merged

Rafael-SOWNet merged 1 commit into
masterfrom
feat/domain-condition-in-a-reading

Conversation

@Rafael-SOWNet

Copy link
Copy Markdown
Member

arcsin is defined on |x| <= 1 over the reals and everywhere over the complex plane. Neither
is the domain of arcsin. #721 asks that an expression not answer only one of them, and the
measurement recorded on that issue found both reference systems take the reading as an
argument — continuous_domain(f, x, S.Reals), FunctionDomain[f, x, dom].

Most of it was already built — and it did not reach

Every node with two answers already writes them both and selects with its own Codomain;
WithCodomain sets it. What could not be done was to ask a tree:

(arcsin(x) + arcsin(y)).WithCodomain(Domain.Real).DomainCondition   // True

The sum has no condition of its own, so the reading never reaches the two arcsines. Asking for
the real reading and silently getting the complex one underneath is exactly the drift #721 is
about.

DomainConditionIn(Domain) applies the reading throughout:

complex real
arcsin(x) True abs(x) <= 1
arcsec(x) not x = 0 abs(x) >= 1
log(b, x) not b = 0 and not b = 1 and not x = 0 b > 0 and not b = 1 and x > 0
arcsin(x) + arcsin(y) True abs(x) <= 1 and abs(y) <= 1
arcsin(x) / y not y = 0 not y = 0 and abs(x) <= 1
sqrt(x) + arcsin(y) True x >= 0 and abs(y) <= 1

The reading is applied where a node's codomain is wider and nowhere else, so a variable
declared over ZZ is not widened to RR by being asked about the reals.

Two deliberate choices

DomainCondition is untouched — same value, same caching, same callers. This is additive.

It deliberately does not make the property consult MathS.Settings.Codomain, which the
issue comment suggested for compatibility. That setting is a thread-static and the property is
cached per instance; a cached value that depends on an ambient setting is wrong the moment the
setting changes. Both systems measured on the issue pass the reading explicitly, so that is what
this does.

Powf gained the real branch it never had, which is the whole of what sqrt is: an even
root of a negative is not real.

real
sqrt(x), x ^ (1/4) x >= 0
x ^ (1/3), x ^ (2/3) True — an odd denominator stays on the line
x ^ y unchanged — a symbolic exponent is not guessed at

The exponent's denominator decides it and only a literal rational has one to read. A symbolic
exponent keeps the condition it had: too strict is a wrong answer here, because this is what
a rewrite consults before firing.

Full suite: 8736 passed, 0 failed.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Bjumi5K7fg8yx6UK1mZTQd

…the expression (#721)

`arcsin` is defined on `|x| <= 1` over the reals and everywhere over the complex plane.
Neither is *the* domain of `arcsin`, and #721 asks that an expression not answer only one
of them -- measured there against SymPy's `continuous_domain(f, x, S.Reals)` and
Mathematica's `FunctionDomain[f, x, dom]`, both of which take the reading as an argument.

**Most of that was already built.** Every node with two answers already writes them both
and selects with its own `Codomain`, and `WithCodomain` sets it. What could not be done was
to ask a *tree*: `WithCodomain` replaces the root's reading and leaves every child on its
own, so

    (arcsin(x) + arcsin(y)).WithCodomain(Real).DomainCondition   ==>   True

because the sum has no condition of its own and the two arcsines were never asked. Asking
for the real reading and being given the complex one underneath is exactly the drift that
issue is about, and it is silent.

`DomainConditionIn(Domain)` applies the reading throughout, and that same expression is
`abs(x) <= 1 and abs(y) <= 1`. The reading is applied where a node's codomain is *wider*
and nowhere else, so a variable declared over `ZZ` is not widened to `RR` by being asked a
question about the reals.

`DomainCondition` is untouched -- same value, same caching, same callers. This is additive,
and deliberately does not make the property consult `MathS.Settings.Codomain`: that is a
thread-static, the property is cached per instance, and a cached value that depends on an
ambient setting is wrong as soon as the setting changes. Both systems measured on the issue
pass the reading explicitly, so that is what this does.

**And `Powf` gained the real branch it never had**, which is the whole of what `sqrt` is:
an even root of a negative is not real, so `x ^ (1/2)` needs `x >= 0` while `x ^ (1/3)`
needs nothing. The exponent's denominator decides it, and only a literal rational has one
to read -- a symbolic exponent keeps the condition it had rather than being guessed at,
since too strict is a wrong answer where a rewrite consults this before firing.
@Rafael-SOWNet
Rafael-SOWNet merged commit 69e4010 into master Aug 27, 2026
31 checks passed
@Rafael-SOWNet
Rafael-SOWNet deleted the feat/domain-condition-in-a-reading branch August 27, 2026 11:47
Rafael-SOWNet added a commit that referenced this pull request Sep 5, 2026
Packaging.md 7 proposed 'a check that fails on the commit that adds a
dependency rather than on the release that ships it', and 11 states the
kernel's third-party set as a list of four whose growth is a packaging
decision. Neither was enforced by anything. KernelDependenciesTest is that
check: the referenced assemblies against a written list, and the four
non-System ones separately, because those are what a consumer's restore
actually fetches.

Writing it found the drift it exists to catch, which had already happened.
The document said 13 referenced assemblies and the count was 14 --
System.Text.Json arrived with Core/Serialization. A framework assembly, so no
consumer's restore changed and nothing noticed, which is the difference
between no harm done and noticed. The list in 7 was a version behind for the
same reason, and the reverse assertion turned up System.Runtime.InteropServices
recorded and no longer referenced.

Asserted in both directions, so a dependency that goes away is deleted rather
than left asserting nothing. It sees one target framework, the one UnitTests
builds; the netstandard2.0 leg is checked by nothing and that is recorded as
its own gap rather than papered over here.

Also corrects AGENTS.md's 'Decisions only a major version may take', which was
wrong on two of its three entries. #721 was done additively in #1090 and is
closed. #204 is no longer a value question: sqrt(x) and x ^ (1/2) are the same
entity -- == answers True and Complexity is 3 for both -- since 1/2 started
parsing as a Rational in 2.3.0, so only the printed form differs. Measured,
both of them, rather than read off the list.

Part of #1008.

Full suite 9562 passed, 0 failed.


Claude-Session: https://claude.ai/code/session_012sonx8iAspMiwRwokT1Ura

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant