Skip to content

Commit b355729

Browse files
committed
Do not simplify x in {1} to false
1 parent 87dcce8 commit b355729

34 files changed

+657
-1324
lines changed

Sources/AngouriMath/Convenience/MathS.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3324,7 +3324,7 @@ public static (Variable, Variable, Variable, Variable, Variable) Var(string name
33243324

33253325
// Undefined
33263326
/// <summary>
3327-
/// That is both undefined and indeterminite
3327+
/// NaN represents both "undefined" and "indeterminate".
33283328
/// Any operation on NaN returns NaN
33293329
/// </summary>
33303330
/// <example>

Sources/AngouriMath/Core/Entity/Continuous/Entity.Continuous.Complex.Definition.cs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -71,11 +71,6 @@ private protected Complex(Real? real, Real? imaginary) =>
7171
/// </summary>
7272
public new bool IsZero => RealPart.EDecimal.IsZero && ImaginaryPart.EDecimal.IsZero;
7373

74-
/// <summary>
75-
/// Checks whether the given number is undefined
76-
/// </summary>
77-
public bool IsNaN => this == Real.NaN;
78-
7974
/// <summary>
8075
/// Creates an instance of Complex
8176
/// </summary>

Sources/AngouriMath/Core/Entity/Continuous/Entity.Continuous.Real.Definition.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ public partial record Real : Complex, System.IComparable<Real>
2828
private protected Real(EDecimal @decimal) : base(null, null) => EDecimal = @decimal;
2929

3030
/// <summary>
31-
/// The PeterO number representation in decimal
31+
/// The PeterO number representation in <see cref="PeterO.Numbers.EDecimal"/>
3232
/// </summary>
3333
public EDecimal EDecimal { get; }
3434

Sources/AngouriMath/Core/Entity/Continuous/Number/Operators.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,8 @@ static Complex BinaryIntPow(Complex num, EInteger val)
373373
if (@base is Real { EDecimal: { IsNegative: false } realBase } && power is Real { EDecimal: var realPower })
374374
return realBase.Pow(realPower, context);
375375
// From https://source.dot.net/#System.Runtime.Numerics/System/Numerics/Complex.cs,7dc9c2ee4f99814a
376+
// NOTE: System.Numerics.Complex.Pow(0, System.Numerics.Complex(-2, 1)) gives 0 + 0i despite being mathematically undefined
377+
// NOTE: System.Numerics.Complex.Pow(0, 0) gives 1 + 0i despite being mathematically undefined
376378
var baseReal = @base.RealPart.EDecimal;
377379
var baseImaginary = @base.ImaginaryPart.EDecimal;
378380
var powerReal = power.RealPart.EDecimal;

Sources/AngouriMath/Core/Entity/Entity.Definition.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -705,5 +705,10 @@ public IReadOnlyList<Variable> Vars
705705
/// </code>
706706
/// </example>
707707
public bool IsConstantLeaf => this is Boolean or Number or Set.SpecialSet;
708+
709+
/// <summary>
710+
/// Checks whether this entity represents the undefined value (<see cref="MathS.NaN"/>).
711+
/// </summary>
712+
public bool IsNaN => this == Real.NaN;
708713
}
709714
}

Sources/AngouriMath/Core/Entity/Omni/Entity.Omni.Classes.cs

Lines changed: 17 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
using HonkSharp.Laziness;
1515
using Complex = AngouriMath.Entity.Number.Complex;
1616
using System.Linq.Expressions;
17+
using System.Diagnostics.CodeAnalysis;
1718

1819
namespace AngouriMath
1920
{
@@ -53,7 +54,7 @@ public FiniteSet Apply(Func<Entity, Entity> func)
5354
var changed = func(el);
5455
if (!ReferenceEquals(changed, el))
5556
hasAnythingChanged = true;
56-
newElements.Add(changed);
57+
if (changed != MathS.NaN) newElements.Add(changed);
5758
}
5859
if (hasAnythingChanged)
5960
return newElements.ToFiniteSet();
@@ -123,31 +124,26 @@ internal static FiniteSet Unite(FiniteSet A, FiniteSet B)
123124
=> new FiniteSet(A.Elements.Concat(B.Elements));
124125

125126
// It could be written with one chain request, but readability > one line
126-
internal static FiniteSet Subtract(FiniteSet A, FiniteSet B)
127+
internal static bool TryFullSubtract(FiniteSet A, FiniteSet B, [NotNullWhen(true)] out FiniteSet? resultSet)
127128
{
129+
var constantSets = A.Vars.Count == 0 && B.Vars.Count == 0;
128130
var dict = BuildDictionaryFromElements(A.Elements, noCheck: true);
129131
foreach (var el in B)
130-
dict.Remove(el.Evaled);
131-
return new FiniteSet(dict.Values, noCheck: true); // we didn't add anything
132-
}
133-
134-
internal static FiniteSet Intersect(FiniteSet A, FiniteSet B)
135-
{
136-
var dict = BuildDictionaryFromElements(A.Elements, noCheck: true);
137-
foreach (var el in A.elements)
138-
if (!B.Contains(el.Key))
139-
dict.Remove(el.Key);
140-
return new FiniteSet(dict.Values, noCheck: true); // we didn't add anything
132+
if (!dict.Remove(el.Evaled) && !constantSets) { resultSet = null; return false; }
133+
resultSet = new FiniteSet(dict.Values, noCheck: true); // we didn't add anything
134+
return true;
141135
}
142136

143137
/// <inheritdoc/>
144138
public override bool TryContains(Entity entity, out bool contains)
145139
{
140+
if (IsSetEmpty) { contains = false; return true; } // a in {} is unambiguously false
146141
contains = elements.ContainsKey(entity.Evaled);
147-
// a in { 2, 3 } is false
148-
// 4 in { a, 3 } is false
149-
// TODO: should we return false when there are symbolic expressions?
150-
return true;
142+
// x in { x, 2 } and 2 in { x, 2 } are both unambiguously true
143+
if (contains) return true;
144+
// however, 1 in { x, 2 }, y in { x, 2 } are both unknown
145+
// meanwhile, 2 in { 1, 3 } is unambiguously false
146+
return entity.Vars.Count == 0 && elements.Keys.All(el => el.Vars.Count == 0);
151147
}
152148

153149
/// <inheritdoc/>
@@ -168,7 +164,7 @@ public bool Equals(FiniteSet? other)
168164
if (other.Count != Count)
169165
return false;
170166
foreach (var pair in elements)
171-
if (!other.Contains(pair.Key))
167+
if (!other.TryContains(pair.Key, out var contains) || !contains)
172168
return false;
173169
return true;
174170
}
@@ -653,13 +649,9 @@ public override Entity Replace(Func<Entity, Entity> func)
653649
public override bool TryContains(Entity entity, out bool contains)
654650
{
655651
contains = false;
656-
if (Left is not Set left || Right is not Set right)
657-
return false;
658-
if (left.TryContains(entity, out var leftContains) && right.TryContains(entity, out var rightContains))
659-
{
660-
contains = leftContains || rightContains;
661-
return true;
662-
}
652+
if (Left is not Set left || Right is not Set right) return false;
653+
if (left.TryContains(entity, out contains) && contains) return true;
654+
if (right.TryContains(entity, out contains)) return true;
663655
return false;
664656
}
665657

Sources/AngouriMath/Core/Entity/Omni/Entity.Omni.Definition.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,12 @@ public Entity In(Entity supSet)
2222
=> new Inf(this, supSet);
2323

2424
/// <summary>
25-
/// Creates a node of a expression assuming some condition
25+
/// Creates a node of a expression assuming some condition. If the condition is the true node, the node itself is returned.
2626
/// </summary>
2727
/// <param name="that">
2828
/// A condition under which a given expression (this) is valid.
2929
/// </param>
3030
/// <returns>A node</returns>
31-
public Entity Provided(Entity that)
32-
=> new Providedf(this, that);
31+
public Entity Provided(Entity that) => that == Boolean.True ? this : new Providedf(this, that);
3332
}
3433
}

Sources/AngouriMath/Core/Entity/Omni/Sets/SetOperators.Intersection.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,6 @@ internal static partial class SetOperators
1414
{
1515
internal static Set IntersectFiniteSetAndSet(FiniteSet finite, Set set)
1616
{
17-
if (set is FiniteSet another)
18-
return FiniteSet.Intersect(finite, another);
1917
var fsb = new FiniteSetBuilder();
2018
var amb = new FiniteSetBuilder();
2119
foreach (var elem in finite)

Sources/AngouriMath/Core/Entity/Omni/Sets/SetOperators.SetSubtraction.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ internal static partial class SetOperators
1414
{
1515
internal static Set SetSubtractSetAndFiniteSet(Set set, FiniteSet finite)
1616
{
17-
if (set is FiniteSet another)
18-
return FiniteSet.Subtract(another, finite);
17+
if (set is FiniteSet another && FiniteSet.TryFullSubtract(another, finite, out var result))
18+
return result;
1919
var fsb = new FiniteSetBuilder(finite);
2020
foreach (var el in finite)
2121
if (set.TryContains(el, out var contains) && !contains)

Sources/AngouriMath/Functions/Continuous/Differentiation.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ partial record Powf
136136
/// <inheritdoc/>
137137
protected override Entity InnerDifferentiate(Variable variable) =>
138138
Exponent == Integer.One
139-
? Base.InnerDifferentiate(variable).WithCondition(Base.DomainCondition) // don't create x^0 which is undefined for x=0
139+
? Base.InnerDifferentiate(variable).Provided(Base.DomainCondition) // don't create x^0 which is undefined for x=0
140140
: Exponent is Number exp
141141
? exp * Base.Pow(exp - 1) * Base.InnerDifferentiate(variable)
142142
: Base is Number

0 commit comments

Comments
 (0)