Skip to content

DomainCondition says log(-3, -3) is defined nowhere and it evaluates to 1; log(1, 1) is 0 and should be NaN #890

Description

@Rafael-SOWNet

Entity.DomainCondition and evaluation disagree about where log is defined, in both directions, and one of the disagreements is a wrong answer.

Measured on master (f2594259), .NET 10, default MathS.Settings.Codomain (Domain.Complex):

expression DomainCondition Evaled what it should be
log(b, x) b > 0 and not b = 1 and x > 0
log(-3, -3) False 1 1 — the condition is wrong
log(-1, -1) False 1 1 — likewise
log(1, 1) False 0 NaN — the value is wrong
log(1, 2) False +oo unsigned/complex infinity
log(0, 2) False 0
log(2, 0) False -oo

Two separate defects, and they point opposite ways.

1. The declared domain is too small

log_b(z) is ln z / ln b, and over the complex plane that is defined and single-valued whenever
z != 0 and ln b != 0 — so for a negative base and argument too: ln(-3)/ln(-3) is exactly
1. DomainCondition says False, i.e. "this expression has a value nowhere", while Evaled
returns 1 and Simplify returns 1.

Logf's IntrinsicCondition is written for the real reading (b > 0, x > 0) while the default
codomain is complex, and nothing reconciles the two. sqrt goes the other way — DomainCondition
of sqrt(x) is True, the complex reading — so the two functions do not even agree with each
other.

Why it matters beyond tidiness. DomainCondition is what a rewrite is supposed to consult to
decide whether it may fire and what condition to attach; that is obligation O5 in
SimplificationContract.md. A rule that
trusts it inherits the over-strong condition, which is exactly what has happened to
log_b(b) -> 1:

"log(x, x)".Simplify()   =>   1 provided x > 0

At x = -3 the expression is 1 and the simplification says it is undefined. That is the mirror of
the usual defect — it turns a value into undefined rather than the other way round — and it was
found by work/boundcheck, which is why this issue exists.

2. log(1, 1) is 0, and should be NaN

ln 1 is 0 exactly, so log_1(1) is 0/0. SymPy gives nan and Mathematica Indeterminate.
Returning 0 is a wrong answer in the sense AGENTS.md
means it: a definite value where none exists. It is not shielded by the domain condition, which
already excludes b = 1 — evaluation simply does not consult it.

log(1, 2) giving +oo is a milder version of the same thing: dividing by ln 1 = 0 has no signed
answer, and both SymPy and Mathematica report an unsigned complex infinity.

What needs deciding, and what does not

The wrong answer at log(1, 1) needs no decision — 0/0 is not 0.

The domain is a decision, and it is the one #721
is about: DomainCondition is fixed at construction and cannot read
MathS.Settings.Codomain, so it cannot say "defined here, given that we are doing real analysis".
Either it becomes codomain-aware, or it commits to the complex reading and the real-analysis
restriction moves to where the codomain is known. Picking one is a maintainer's call; what is not in
question is that a single expression should not be declared undefined everywhere and simultaneously
evaluate to 1.

Related: #887 records the log(x, x)
symptom, and #884 is the other logarithm
rule whose assumption is not stated.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions