Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Sources/AngouriMath/Convenience/MathS.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3324,7 +3324,7 @@ public static (Variable, Variable, Variable, Variable, Variable) Var(string name

// Undefined
/// <summary>
/// That is both undefined and indeterminite
/// NaN represents both "undefined" and "indeterminate".
/// Any operation on NaN returns NaN
/// </summary>
/// <example>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,11 +71,6 @@ private protected Complex(Real? real, Real? imaginary) =>
/// </summary>
public new bool IsZero => RealPart.EDecimal.IsZero && ImaginaryPart.EDecimal.IsZero;

/// <summary>
/// Checks whether the given number is undefined
/// </summary>
public bool IsNaN => this == Real.NaN;

/// <summary>
/// Creates an instance of Complex
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public partial record Real : Complex, System.IComparable<Real>
private protected Real(EDecimal @decimal) : base(null, null) => EDecimal = @decimal;

/// <summary>
/// The PeterO number representation in decimal
/// The PeterO number representation in <see cref="PeterO.Numbers.EDecimal"/>
/// </summary>
public EDecimal EDecimal { get; }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,8 @@ static Complex BinaryIntPow(Complex num, EInteger val)
if (@base is Real { EDecimal: { IsNegative: false } realBase } && power is Real { EDecimal: var realPower })
return realBase.Pow(realPower, context);
// From https://source.dot.net/#System.Runtime.Numerics/System/Numerics/Complex.cs,7dc9c2ee4f99814a
// NOTE: System.Numerics.Complex.Pow(0, System.Numerics.Complex(-2, 1)) gives 0 + 0i despite being mathematically undefined
// NOTE: System.Numerics.Complex.Pow(0, 0) gives 1 + 0i despite being mathematically undefined
var baseReal = @base.RealPart.EDecimal;
var baseImaginary = @base.ImaginaryPart.EDecimal;
var powerReal = power.RealPart.EDecimal;
Expand Down
5 changes: 5 additions & 0 deletions Sources/AngouriMath/Core/Entity/Entity.Definition.cs
Original file line number Diff line number Diff line change
Expand Up @@ -705,5 +705,10 @@ public IReadOnlyList<Variable> Vars
/// </code>
/// </example>
public bool IsConstantLeaf => this is Boolean or Number or Set.SpecialSet;

/// <summary>
/// Checks whether this entity represents the undefined value (<see cref="MathS.NaN"/>).
/// </summary>
public bool IsNaN => this == Real.NaN;
}
}
42 changes: 17 additions & 25 deletions Sources/AngouriMath/Core/Entity/Omni/Entity.Omni.Classes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
using HonkSharp.Laziness;
using Complex = AngouriMath.Entity.Number.Complex;
using System.Linq.Expressions;
using System.Diagnostics.CodeAnalysis;

namespace AngouriMath
{
Expand Down Expand Up @@ -53,7 +54,7 @@ public FiniteSet Apply(Func<Entity, Entity> func)
var changed = func(el);
if (!ReferenceEquals(changed, el))
hasAnythingChanged = true;
newElements.Add(changed);
if (changed != MathS.NaN) newElements.Add(changed);
}
if (hasAnythingChanged)
return newElements.ToFiniteSet();
Expand Down Expand Up @@ -123,31 +124,26 @@ internal static FiniteSet Unite(FiniteSet A, FiniteSet B)
=> new FiniteSet(A.Elements.Concat(B.Elements));

// It could be written with one chain request, but readability > one line
internal static FiniteSet Subtract(FiniteSet A, FiniteSet B)
internal static bool TryFullSubtract(FiniteSet A, FiniteSet B, [NotNullWhen(true)] out FiniteSet? resultSet)
{
var constantSets = A.Vars.Count == 0 && B.Vars.Count == 0;
var dict = BuildDictionaryFromElements(A.Elements, noCheck: true);
foreach (var el in B)
dict.Remove(el.Evaled);
return new FiniteSet(dict.Values, noCheck: true); // we didn't add anything
}

internal static FiniteSet Intersect(FiniteSet A, FiniteSet B)
{
var dict = BuildDictionaryFromElements(A.Elements, noCheck: true);
foreach (var el in A.elements)
if (!B.Contains(el.Key))
dict.Remove(el.Key);
return new FiniteSet(dict.Values, noCheck: true); // we didn't add anything
if (!dict.Remove(el.Evaled) && !constantSets) { resultSet = null; return false; }
resultSet = new FiniteSet(dict.Values, noCheck: true); // we didn't add anything
return true;
}

/// <inheritdoc/>
public override bool TryContains(Entity entity, out bool contains)
{
if (IsSetEmpty) { contains = false; return true; } // a in {} is unambiguously false
contains = elements.ContainsKey(entity.Evaled);
// a in { 2, 3 } is false
// 4 in { a, 3 } is false
// TODO: should we return false when there are symbolic expressions?
return true;
// x in { x, 2 } and 2 in { x, 2 } are both unambiguously true
if (contains) return true;
// however, 1 in { x, 2 }, y in { x, 2 } are both unknown
// meanwhile, 2 in { 1, 3 } is unambiguously false
return entity.Vars.Count == 0 && elements.Keys.All(el => el.Vars.Count == 0);
}

/// <inheritdoc/>
Expand All @@ -168,7 +164,7 @@ public bool Equals(FiniteSet? other)
if (other.Count != Count)
return false;
foreach (var pair in elements)
if (!other.Contains(pair.Key))
if (!other.TryContains(pair.Key, out var contains) || !contains)
return false;
return true;
}
Expand Down Expand Up @@ -653,13 +649,9 @@ public override Entity Replace(Func<Entity, Entity> func)
public override bool TryContains(Entity entity, out bool contains)
{
contains = false;
if (Left is not Set left || Right is not Set right)
return false;
if (left.TryContains(entity, out var leftContains) && right.TryContains(entity, out var rightContains))
{
contains = leftContains || rightContains;
return true;
}
if (Left is not Set left || Right is not Set right) return false;
if (left.TryContains(entity, out contains) && contains) return true;
if (right.TryContains(entity, out contains)) return true;
return false;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,12 @@ public Entity In(Entity supSet)
=> new Inf(this, supSet);

/// <summary>
/// Creates a node of a expression assuming some condition
/// Creates a node of a expression assuming some condition. If the condition is the true node, the node itself is returned.
/// </summary>
/// <param name="that">
/// A condition under which a given expression (this) is valid.
/// </param>
/// <returns>A node</returns>
public Entity Provided(Entity that)
=> new Providedf(this, that);
public Entity Provided(Entity that) => that == Boolean.True ? this : new Providedf(this, that);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@ internal static partial class SetOperators
{
internal static Set IntersectFiniteSetAndSet(FiniteSet finite, Set set)
{
if (set is FiniteSet another)
return FiniteSet.Intersect(finite, another);
var fsb = new FiniteSetBuilder();
var amb = new FiniteSetBuilder();
foreach (var elem in finite)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ internal static partial class SetOperators
{
internal static Set SetSubtractSetAndFiniteSet(Set set, FiniteSet finite)
{
if (set is FiniteSet another)
return FiniteSet.Subtract(another, finite);
if (set is FiniteSet another && FiniteSet.TryFullSubtract(another, finite, out var result))
return result;
var fsb = new FiniteSetBuilder(finite);
foreach (var el in finite)
if (set.TryContains(el, out var contains) && !contains)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ partial record Powf
/// <inheritdoc/>
protected override Entity InnerDifferentiate(Variable variable) =>
Exponent == Integer.One
? Base.InnerDifferentiate(variable).WithCondition(Base.DomainCondition) // don't create x^0 which is undefined for x=0
? Base.InnerDifferentiate(variable).Provided(Base.DomainCondition) // don't create x^0 which is undefined for x=0
: Exponent is Number exp
? exp * Base.Pow(exp - 1) * Base.InnerDifferentiate(variable)
: Base is Number
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ internal static class LimitSolvers
var divEvaled = div.Evaled;
return divEvaled switch
{
{ Evaled: Complex { IsNaN: true } } => null,
{ Evaled.IsNaN: true } => null,
{ } res when res.ContainsNode("+oo") || res.ContainsNode("-oo") => div.InnerSimplified,
{ Evaled: Complex } limit => limit,
_ => upperLogLimit / lowerLogLimit,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ private static Entity ExpandLogarithm(Entity expr)
{
_ when !expr.ContainsNode(x) => expr,
// avoid NaN values as non finite numbers
Real { IsNaN: true } => Real.NaN,
{ IsNaN: true } => MathS.NaN,
// if x -> -oo just make -x -> +oo
Real { IsFinite: false, IsNegative: true } => SimplifyAndComputeLimitToInfinity(expr.Substitute(x, -x), x),
// compute limit for x -> +oo
Expand Down
11 changes: 11 additions & 0 deletions Sources/AngouriMath/Functions/Continuous/Solvers/EquationSolver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -103,5 +103,16 @@ internal static List<List<Entity>> InSolveSystem(List<Entity> equations, ReadOnl
}
return result;
}
internal static Set SolvePiecewise(Piecewise piecewise, Variable x, Func<Entity, Variable, Set> solve)
{
Entity cond = true;
var res = new List<Set>();
foreach (var c in piecewise.Cases)
{
res.Add(solve(c.Expression, x).Filter(c.Predicate & cond, x));
cond &= !c.Predicate;
}
return res.Unite();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,13 @@
// Website: https://am.angouri.org.
//

using static AngouriMath.Entity;
using AngouriMath.Functions.Algebra;
using AngouriMath.Extensions;
using static AngouriMath.Entity.Set;
using AngouriMath.Core.Exceptions;
using AngouriMath.Core.Multithreading;
using AngouriMath.Extensions;
using AngouriMath.Functions.Algebra;
using System.Linq.Expressions;
using static AngouriMath.Entity;
using static AngouriMath.Entity.Set;

namespace AngouriMath
{
Expand Down Expand Up @@ -76,17 +77,6 @@ namespace AngouriMath.Functions.Algebra.AnalyticalSolving
{
internal static class AnalyticalEquationSolver
{
private static Set PiecewiseIntoIndependentEquations(Piecewise leftPart, Variable x, Entity rightPart)
{
Entity cond = true;
var res = new List<Set>();
foreach (var c in leftPart.Cases)
{
res.Add(Solve(c.Expression - rightPart, x).Filter(c.Predicate & cond, x));
cond &= !c.Predicate;
}
return res.Unite();
}

/// <summary>Equation solver</summary>
/// <param name="compensateSolving">
Expand All @@ -98,12 +88,10 @@ private static Set PiecewiseIntoIndependentEquations(Piecewise leftPart, Variabl
/// <param name="x">Variable to solve over</param>
internal static Set Solve(Entity expr, Variable x, bool compensateSolving = false)
{
if (!compensateSolving) expr = expr.InnerSimplified; // don't simplify away the 0 on the right hand side of the subtraction
if (expr == x)
return new Entity[] { 0 }.ToSet();

if (ProvidedLifter.ExtractProvidedPredicates(ref expr, out var predicate))
return ProvidedLifter.MergePredicateIntoSolveResult(Solve(expr, x, compensateSolving), x, predicate);

// Applies an attempt to downcast roots
static Entity TryDowncast(Entity equation, Variable x, Entity root)
{
Expand All @@ -122,17 +110,9 @@ static Entity TryDowncast(Entity equation, Variable x, Entity root)

switch (expr)
{
case Mulf(var multiplier, var multiplicand):
return MathS.Union(Solve(multiplier, x), Solve(multiplicand, x));
case Divf(var dividend, var divisor):
return MathS.SetSubtraction(Solve(dividend, x), Solve(divisor, x));
case Powf(var @base, _):
return Solve(@base, x);
case Minusf(var subtrahend, var minuend) when !minuend.ContainsNode(x) && compensateSolving:
if (subtrahend == x)
return new[] { minuend }.ToSet();
if (subtrahend is Piecewise piecewise)
return PiecewiseIntoIndependentEquations(piecewise, x, minuend);
Entity? lastChild = null;
foreach (var child in subtrahend.DirectChildren)
if (child.ContainsNode(x))
Expand All @@ -145,6 +125,10 @@ static Entity TryDowncast(Entity equation, Variable x, Entity root)
return subtrahend.Invert(minuend, lastChild).Select(result => Solve(lastChild - result, x, compensateSolving: true)).Unite();
case Function:
return expr.Invert(0, x).Select(ent => TryDowncast(expr, x, ent)).ToSet();
case Providedf(var expression, var predicate):
return Solve(expression, x, compensateSolving).Filter(predicate, x);
case Piecewise p:
return EquationSolver.SolvePiecewise(p, x, (e, x) => Solve(e, x, compensateSolving));
default:
break;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -441,19 +441,19 @@ private protected override IEnumerable<Entity> InvertNode(Entity value, Entity x
var (withX, withoutX) = Left.ContainsNode(x) ? (Left, Right) : (Right, Left);
if (value is FiniteSet valueFiniteSet && withoutX is FiniteSet A)
{
if (!A.TryIsSubsetOf(valueFiniteSet, out var isSub))
return withX.InvertNode(value.SetSubtract(withoutX), x);
if (!isSub)
return Empty;
var sub = FiniteSet.Subtract(valueFiniteSet, A);
var answers = new List<Entity>();
foreach (var ans in A.GetPowerSet())
if (A.TryIsSubsetOf(valueFiniteSet, out var isSub) && isSub &&
FiniteSet.TryFullSubtract(valueFiniteSet, A, out var sub))
{
if (ans is not FiniteSet finiteSet)
throw new AngouriBugException("PowerSet must return a set of sets");
answers.AddRange(withX.InvertNode(FiniteSet.Unite(sub, finiteSet), x));
var answers = new List<Entity>();
foreach (var ans in A.GetPowerSet())
{
if (ans is not FiniteSet finiteSet)
throw new AngouriBugException("PowerSet must return a set of sets");
answers.AddRange(withX.InvertNode(FiniteSet.Unite(sub, finiteSet), x));
}
return answers;
}
return answers;
else return Empty;
}
return withX.InvertNode(value.SetSubtract(withoutX), x);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,9 @@ internal static Set Solve(Entity expr, Variable x)
Variable when expr == x => new FiniteSet(true),

Inf(var var, Set set) when var == x => set,

Providedf(var inner, var predicate) => ProvidedLifter.MergePredicateIntoSolveResult(Solve(inner, x), x, predicate),

Providedf(var e, var predicate) => Solve(e, x).Filter(predicate, x),
Piecewise p => EquationSolver.SolvePiecewise(p, x, Solve),

// TODO: Although piecewise needed?
_ => Set.Empty
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,11 @@ internal static class AnalyticalInequalitySolver
/// </summary>
internal static Set Solve(Entity expr, Variable x)
{
if (ProvidedLifter.ExtractProvidedPredicates(ref expr, out var predicate))
return ProvidedLifter.MergePredicateIntoSolveResult(Solve(expr, x), x, predicate);
switch (expr)
{
case Providedf(var e, var predicate): return Solve(e, x).Filter(predicate, x);
case Piecewise p: return EquationSolver.SolvePiecewise(p, x, Solve);
}
{
if (MathS.Utils.TryGetPolyLinear(expr, x, out var a, out var b))
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
//

using AngouriMath.Extensions;
using AngouriMath.Functions.Algebra;
using static AngouriMath.Entity;
using static AngouriMath.Entity.Set;

Expand All @@ -15,10 +16,14 @@ internal static class AnalyticalSetSolver
{
internal static Set Solve(Entity left, Entity right, Variable x)
{
if (ProvidedLifter.ExtractProvidedPredicates(ref left, out var predicate))
return ProvidedLifter.MergePredicateIntoSolveResult(Solve(left, right, x), x, predicate);
if (ProvidedLifter.ExtractProvidedPredicates(ref right, out predicate))
return ProvidedLifter.MergePredicateIntoSolveResult(Solve(left, right, x), x, predicate);
switch (left, right)
{
case (Providedf(var l, var predicate), _): return Solve(l, right, x).Filter(predicate, x);
case (_, Providedf(var r, var predicate)): return Solve(left, r, x).Filter(predicate, x);
case (Piecewise p, _): return EquationSolver.SolvePiecewise(p, x, (e, x) => Solve(e, right, x));
case (_, Piecewise p): return EquationSolver.SolvePiecewise(p, x, (e, x) => Solve(left, e, x));
}

left = left.Replace(Patterns.SetOperatorRules);
right = right.Replace(Patterns.SetOperatorRules);
if (left.DirectChildren.Count<Entity>(c => c == x)
Expand Down
Loading
Loading