Ask whether it is a member, not whether it might be (#995) - #997
Ask whether it is a member, not whether it might be (#995)#997Rafael-SOWNet wants to merge 1 commit into
Conversation
`SpecialSet.TryContains` decided membership by calling `MayContain`, whose
answer is deliberately permissive: every one of the five is written as
`entity is <that kind> || !entity.IsConstantLeaf`. That is what its other
caller wants -- `DomainsFunctional.FitsDomainOrNonNumeric` guards a codomain,
where letting through what has not been ruled out is the safe direction --
but membership is the opposite question, and its `out bool` is a decision.
So everything closed that was not a constant leaf was a member of every
special set at once:
[1, 2] in BB -> True
[1, 2] in ZZ -> True
[1, 2] in RR -> True
[1, 2] in (ZZ /\ BB) -> True
{ 1, 2 } in RR -> True
The symbolic guard above it is why this went unseen: anything with a variable
is declined before `MayContain` is reached, and every numeric value is a
constant leaf, so only matrices, finite sets and intervals took the permissive
branch -- and for those the answer is available and is False. A matrix is not
a real number, and that is decided rather than unknown.
`MayContain` is unchanged, and so is every answer for a number or a boolean.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KbKcbJP266A3EGyQ5kq7Ru
|
Against the two PRs already open, this conflicts in one file —
Resolution is "keep both row sets"; the one row that goes is #990's All three compose. Built master + #990 + #991 + #997 on a throwaway branch and ran the suite: 7466 passed, 0 failed, 14 skipped. Spot-checks on that build: The last two are where the two changes meet: Whichever merges last takes the one table conflict; I will do it. |
Fixes #995.
The defect
SpecialSet.TryContainsdecided membership by askingMayContain, and everyMayContainis written to be permissive:IsConstantLeafisBoolean or Number or SpecialSet, so a matrix, a finite set and an interval were all "not ruled out" and therefore members — of every special set, simultaneously:[1, 2] in BBTrueFalse[1, 2] in ZZTrueFalse[1, 2] in QQTrueFalse[1, 2] in RRTrueFalse[1, 2] in CCTrueFalse[1, 2] in (ZZ /\ BB)TrueFalse{ 1, 2 } in RRTrueFalse[0; 1] in RRTrueFalseZZandBBshare no members, so the old answers contradicted each other and nothing could have relied on all of them.Why the two disagree
The two names are asking two different questions, and only one implementation existed for both.
MayContain— might this be a member — is right for its other caller.DomainsFunctional.FitsDomainOrNonNumericguards a codomain, and there the safe direction is to let through whatever has not been ruled out.MayContainis unchanged by this PR.TryContains— is this a member — hands back a decision in anout bool. Reading the permissive result as the decided one turns "I cannot rule this out" into "yes".The symbolic guard above it is why this survived: anything containing a variable is declined before
MayContainis reached, and every numeric value is a constant leaf, so only the closed non-leaves took the permissive branch. For those the right answer is available — a matrix is not a real number — and it isFalse, decided rather than unknown.What did not change
Out of scope, and deliberately:
+oo in CCand0/0 in RRare bothTruetoday. Those are constant leaves, so they go down the other branch — the same question as the-oohalf of the domain-condition discussion, not this one. #995 says so too.Measured
casbench: 116/119, 0 wrong, 0 error, 0 timeout — the standing figure.Sources/Tests/UnitTests/Core/Sets/Contains.cs, covering each special set against a matrix, the intersection, a finite set, an interval, and the leaf answers that must not move.BREAKING-CHANGES.mdentry with both values measured on builds —5211ccd6for the old ones.