diff --git a/Sources/AngouriMath/Convenience/MathS.cs b/Sources/AngouriMath/Convenience/MathS.cs
index 25e3952e6..0b08e8deb 100644
--- a/Sources/AngouriMath/Convenience/MathS.cs
+++ b/Sources/AngouriMath/Convenience/MathS.cs
@@ -5166,10 +5166,11 @@ public static class Matrices
///
public enum Direction
{
-#pragma warning disable CS1591
+ /// Side by side, so the columns of the second follow the first.
Horizontal,
+
+ /// One above the other, so the rows of the second follow the first.
Vertical
-#pragma warning restore CS1591
}
///
diff --git a/Sources/AngouriMath/Core/Entity/Continuous/Entity.Continuous.AbsSignum.Classes.cs b/Sources/AngouriMath/Core/Entity/Continuous/Entity.Continuous.AbsSignum.Classes.cs
index e75e8cd24..3fbe93d9c 100644
--- a/Sources/AngouriMath/Core/Entity/Continuous/Entity.Continuous.AbsSignum.Classes.cs
+++ b/Sources/AngouriMath/Core/Entity/Continuous/Entity.Continuous.AbsSignum.Classes.cs
@@ -11,12 +11,12 @@ namespace AngouriMath
{
partial record Entity
{
-#pragma warning disable CS1591 // only while records' parameters cannot be documented
///
/// A node of signum
///
public sealed partial record Signumf(Entity Argument) : Function, IUnaryNode
{
+ ///
public Entity NodeChild => Argument;
private Signumf New(Entity arg) =>
@@ -32,6 +32,7 @@ private Signumf New(Entity arg) =>
///
public sealed partial record Absf(Entity Argument) : Function, IUnaryNode
{
+ ///
public Entity NodeChild => Argument;
private Absf New(Entity arg) =>
@@ -41,6 +42,5 @@ private Absf New(Entity arg) =>
///
protected override Entity[] InitDirectChildren() => new[] { Argument };
}
-#pragma warning restore CS1591 // only while records' parameters cannot be documented
}
}
diff --git a/Sources/AngouriMath/Core/Entity/Continuous/Entity.Continuous.ArcTrigonometry.Classes.cs b/Sources/AngouriMath/Core/Entity/Continuous/Entity.Continuous.ArcTrigonometry.Classes.cs
index cbfdfdb5e..239903e16 100644
--- a/Sources/AngouriMath/Core/Entity/Continuous/Entity.Continuous.ArcTrigonometry.Classes.cs
+++ b/Sources/AngouriMath/Core/Entity/Continuous/Entity.Continuous.ArcTrigonometry.Classes.cs
@@ -11,12 +11,12 @@ namespace AngouriMath
{
partial record Entity
{
-#pragma warning disable CS1591 // only while records' parameters cannot be documented
///
/// A node of arcsine
///
public sealed partial record Arcsinf(Entity Argument) : TrigonometricFunction, IUnaryNode
{
+ ///
public Entity NodeChild => Argument;
/// Reuse the cache by returning the same object if possible
@@ -32,6 +32,7 @@ public sealed partial record Arcsinf(Entity Argument) : TrigonometricFunction, I
///
public sealed partial record Arccosf(Entity Argument) : TrigonometricFunction, IUnaryNode
{
+ ///
public Entity NodeChild => Argument;
/// Reuse the cache by returning the same object if possible
@@ -47,6 +48,7 @@ public sealed partial record Arccosf(Entity Argument) : TrigonometricFunction, I
///
public sealed partial record Arctanf(Entity Argument) : TrigonometricFunction, IUnaryNode
{
+ ///
public Entity NodeChild => Argument;
/// Reuse the cache by returning the same object if possible
@@ -62,6 +64,7 @@ public sealed partial record Arctanf(Entity Argument) : TrigonometricFunction, I
///
public sealed partial record Arccotanf(Entity Argument) : TrigonometricFunction, IUnaryNode
{
+ ///
public Entity NodeChild => Argument;
/// Reuse the cache by returning the same object if possible
@@ -77,6 +80,7 @@ public sealed partial record Arccotanf(Entity Argument) : TrigonometricFunction,
///
public sealed partial record Arcsecantf(Entity Argument) : TrigonometricFunction, IUnaryNode
{
+ ///
public Entity NodeChild => Argument;
/// Reuse the cache by returning the same object if possible
@@ -92,6 +96,7 @@ public sealed partial record Arcsecantf(Entity Argument) : TrigonometricFunction
///
public sealed partial record Arccosecantf(Entity Argument) : TrigonometricFunction, IUnaryNode
{
+ ///
public Entity NodeChild => Argument;
/// Reuse the cache by returning the same object if possible
@@ -101,6 +106,5 @@ public sealed partial record Arccosecantf(Entity Argument) : TrigonometricFuncti
///
protected override Entity[] InitDirectChildren() => new[] { Argument };
}
-#pragma warning restore CS1591 // only while records' parameters cannot be documented
}
}
diff --git a/Sources/AngouriMath/Core/Entity/Continuous/Entity.Continuous.Calculus.Classes.cs b/Sources/AngouriMath/Core/Entity/Continuous/Entity.Continuous.Calculus.Classes.cs
index ff1dffcf7..08896cf82 100644
--- a/Sources/AngouriMath/Core/Entity/Continuous/Entity.Continuous.Calculus.Classes.cs
+++ b/Sources/AngouriMath/Core/Entity/Continuous/Entity.Continuous.Calculus.Classes.cs
@@ -11,7 +11,6 @@ namespace AngouriMath
{
partial record Entity
{
-#pragma warning disable CS1591 // only while records' parameters cannot be documented
///
/// A node of derivative
///
@@ -64,6 +63,5 @@ public override Entity Replace(Func func) =>
///
protected override Entity[] InitDirectChildren() => new[] { Expression, Var, Destination };
}
-#pragma warning restore CS1591 // only while records' parameters cannot be documented
}
}
diff --git a/Sources/AngouriMath/Core/Entity/Continuous/Entity.Continuous.Complex.Definition.cs b/Sources/AngouriMath/Core/Entity/Continuous/Entity.Continuous.Complex.Definition.cs
index d0e75fd01..2137e6c09 100644
--- a/Sources/AngouriMath/Core/Entity/Continuous/Entity.Continuous.Complex.Definition.cs
+++ b/Sources/AngouriMath/Core/Entity/Continuous/Entity.Continuous.Complex.Definition.cs
@@ -195,55 +195,136 @@ public static bool TryParse(string source,
public System.Numerics.Complex ToNumerics() =>
new System.Numerics.Complex(RealPart.EDecimal.ToDouble(), ImaginaryPart.EDecimal.ToDouble());
-#pragma warning disable CS1591
+ ///
+ /// Narrows to , which is
+ /// and loses precision the same way.
+ ///
public static explicit operator System.Numerics.Complex(Complex it)
=> it.ToNumerics();
+ /// Their sum.
public static Complex operator +(Complex a, Complex b) => OpSum(a, b);
+
+ /// Their difference.
public static Complex operator -(Complex a, Complex b) => OpSub(a, b);
+
+ /// Their product.
public static Complex operator *(Complex a, Complex b) => OpMul(a, b);
+
+ /// Their quotient.
public static Complex operator /(Complex a, Complex b) => OpDiv(a, b);
+
+ /// The operand itself; unary plus changes nothing.
public static Complex operator +(Complex a) => a;
+
+ /// Its negation.
public static Complex operator -(Complex a) => OpMul(Integer.MinusOne, a);
+
+ // The conversions below share one surprise, stated once here and referred to
+ // rather than repeated: where MathS.Settings.DowncastingEnabled is on, which is
+ // the default, an exact whole value arrives as an Integer and an exact ratio as
+ // a Rational. The declared type is Complex either way, so the difference shows
+ // up in the runtime type and in what the number prints as, not in the signature.
+
+ /// The number as a .
public static implicit operator Complex(sbyte value) => (long)value;
+
+ /// The number as a .
public static implicit operator Complex(byte value) => (ulong)value;
+
+ /// The number as a .
public static implicit operator Complex(short value) => (long)value;
+
+ /// The number as a .
public static implicit operator Complex(ushort value) => (ulong)value;
+
+ /// The number as a .
public static implicit operator Complex(int value) => (long)value;
+
+ /// The number as a .
public static implicit operator Complex(uint value) => (ulong)value;
+
+ ///
+ /// The number as a — an at runtime
+ /// while downcasting is enabled.
+ ///
public static implicit operator Complex(long value)
=> MathS.Settings.DowncastingEnabled
? Integer.Create(value)
: Create(value, 0);
+ ///
+ /// The number as a — an at runtime
+ /// while downcasting is enabled.
+ ///
public static implicit operator Complex(ulong value)
=> MathS.Settings.DowncastingEnabled
? Integer.Create(value)
: Create(value, 0);
+
+ ///
+ /// The integer as a — an at runtime
+ /// while downcasting is enabled.
+ ///
public static implicit operator Complex(EInteger value)
=> MathS.Settings.DowncastingEnabled
? Integer.Create(value)
: Create(value, 0);
+
+ ///
+ /// The ratio as a — a at runtime
+ /// while downcasting is enabled, and so still exact.
+ ///
public static implicit operator Complex(ERational value)
=> MathS.Settings.DowncastingEnabled
? Rational.Create(value)
: Create(value, 0);
+
+ /// The decimal as a with no imaginary part.
public static implicit operator Complex(EDecimal value)
=> Create(value, 0);
+
+ ///
+ /// The value as a with no imaginary part. It is read as the
+ /// binary it is, so a literal such as 0.1f arrives
+ /// as the value that literal actually holds and not as one tenth.
+ ///
public static implicit operator Complex(float value)
=> Create(EDecimal.FromSingle(value), 0);
+
+ ///
+ /// The value as a with no imaginary part, read as the
+ /// binary it is rather than as the decimal it was
+ /// written as.
+ ///
public static implicit operator Complex(double value)
=> Create(EDecimal.FromDouble(value), 0);
+
+ ///
+ /// The value as a with no imaginary part. A
+ /// is decimal already, so this one keeps the digits
+ /// that were written.
+ ///
public static implicit operator Complex(decimal value)
=> Create(EDecimal.FromDecimal(value), 0);
+
+ ///
+ /// The .NET complex number as this one, through its two
+ /// parts and their precision.
+ ///
public static implicit operator Complex(System.Numerics.Complex value) =>
Create(EDecimal.FromDouble(value.Real), EDecimal.FromDouble(value.Imaginary));
+
+ /// The pair read as real and imaginary parts.
public static implicit operator Complex((int re, int im) v) => Create(v.re, v.im);
+
+ /// The pair read as real and imaginary parts.
public static implicit operator Complex((float re, float im) v) => Create(v.re, v.im);
- public static implicit operator Complex((decimal re, decimal im) v) => Create(v.re, v.im);
- public static implicit operator Complex((double re, double im) v) => Create(v.re, v.im);
-#pragma warning restore CS1591
+ /// The pair read as real and imaginary parts.
+ public static implicit operator Complex((decimal re, decimal im) v) => Create(v.re, v.im);
+ /// The pair read as real and imaginary parts.
+ public static implicit operator Complex((double re, double im) v) => Create(v.re, v.im);
}
}
}
diff --git a/Sources/AngouriMath/Core/Entity/Continuous/Entity.Continuous.Exponential.Classes.cs b/Sources/AngouriMath/Core/Entity/Continuous/Entity.Continuous.Exponential.Classes.cs
index 7537e1b85..08e5081ec 100644
--- a/Sources/AngouriMath/Core/Entity/Continuous/Entity.Continuous.Exponential.Classes.cs
+++ b/Sources/AngouriMath/Core/Entity/Continuous/Entity.Continuous.Exponential.Classes.cs
@@ -11,7 +11,6 @@ namespace AngouriMath
{
partial record Entity
{
-#pragma warning disable CS1591 // only while records' parameters cannot be documented
///
/// A node of exponential (power)
///
@@ -22,8 +21,10 @@ private Powf New(Entity @base, Entity exponent) =>
ReferenceEquals(Base, @base) && ReferenceEquals(Exponent, exponent) ? this : new(@base, exponent);
internal override Priority Priority => Priority.Pow;
+ ///
public Entity NodeFirstChild => Base;
+ ///
public Entity NodeSecondChild => Exponent;
///
@@ -41,8 +42,10 @@ public sealed partial record Logf(Entity Base, Entity Antilogarithm) : Function,
private Logf New(Entity @base, Entity antilogarithm) =>
ReferenceEquals(Base, @base) && ReferenceEquals(Antilogarithm, antilogarithm) ? this : new(@base, antilogarithm);
+ ///
public Entity NodeFirstChild => Base;
+ ///
public Entity NodeSecondChild => Antilogarithm;
///
@@ -51,6 +54,5 @@ private Logf New(Entity @base, Entity antilogarithm) =>
protected override Entity[] InitDirectChildren() => new[] { Base, Antilogarithm };
}
-#pragma warning restore CS1591 // only while records' parameters cannot be documented
}
}
diff --git a/Sources/AngouriMath/Core/Entity/Continuous/Entity.Continuous.Factorial.Classes.cs b/Sources/AngouriMath/Core/Entity/Continuous/Entity.Continuous.Factorial.Classes.cs
index 8bddb0629..4d4b9280f 100644
--- a/Sources/AngouriMath/Core/Entity/Continuous/Entity.Continuous.Factorial.Classes.cs
+++ b/Sources/AngouriMath/Core/Entity/Continuous/Entity.Continuous.Factorial.Classes.cs
@@ -11,7 +11,6 @@ namespace AngouriMath
{
partial record Entity
{
-#pragma warning disable CS1591 // only while records' parameters cannot be documented
///
/// A node of factorial
///
@@ -22,6 +21,7 @@ public sealed partial record Factorialf(Entity Argument) : Function, IUnaryNode
// This is still a function for pattern replacement
internal override Priority Priority => Priority.Factorial;
+ ///
public Entity NodeChild => Argument;
///
@@ -29,6 +29,5 @@ public sealed partial record Factorialf(Entity Argument) : Function, IUnaryNode
///
protected override Entity[] InitDirectChildren() => new[] { Argument };
}
-#pragma warning restore CS1591 // only while records' parameters cannot be documented
}
}
diff --git a/Sources/AngouriMath/Core/Entity/Continuous/Entity.Continuous.Floors.Classes.cs b/Sources/AngouriMath/Core/Entity/Continuous/Entity.Continuous.Floors.Classes.cs
index 05f94f543..de146b873 100644
--- a/Sources/AngouriMath/Core/Entity/Continuous/Entity.Continuous.Floors.Classes.cs
+++ b/Sources/AngouriMath/Core/Entity/Continuous/Entity.Continuous.Floors.Classes.cs
@@ -11,7 +11,6 @@ namespace AngouriMath
{
partial record Entity
{
-#pragma warning disable CS1591 // only while records' parameters cannot be documented
///
/// A node of floor: the greatest integer not above the argument.
///
@@ -23,6 +22,7 @@ partial record Entity
///
public sealed partial record Floorf(Entity Argument) : Function, IUnaryNode
{
+ ///
public Entity NodeChild => Argument;
private Floorf New(Entity arg) =>
@@ -42,6 +42,7 @@ private Floorf New(Entity arg) =>
///
public sealed partial record Ceilf(Entity Argument) : Function, IUnaryNode
{
+ ///
public Entity NodeChild => Argument;
private Ceilf New(Entity arg) =>
@@ -51,6 +52,5 @@ private Ceilf New(Entity arg) =>
///
protected override Entity[] InitDirectChildren() => new[] { Argument };
}
-#pragma warning restore CS1591 // only while records' parameters cannot be documented
}
}
diff --git a/Sources/AngouriMath/Core/Entity/Continuous/Entity.Continuous.Integer.Definition.cs b/Sources/AngouriMath/Core/Entity/Continuous/Entity.Continuous.Integer.Definition.cs
index bbd1795cd..2a7bb9229 100644
--- a/Sources/AngouriMath/Core/Entity/Continuous/Entity.Continuous.Integer.Definition.cs
+++ b/Sources/AngouriMath/Core/Entity/Continuous/Entity.Continuous.Integer.Definition.cs
@@ -121,15 +121,47 @@ internal static bool TryParse(string s,
///
public Integer IntegerDiv(Integer a) => EInteger.Divide(a.EInteger);
-#pragma warning disable CS1591
+ // Comparison here is on the value and answers a bool, where the same operators
+ // on Entity build an inequality node instead.
+
+ /// Whether the first is strictly greater.
public static bool operator >(Integer a, Integer b) => a.EInteger.CompareTo(b.EInteger) > 0;
+
+ /// Whether the first is greater or they are equal.
public static bool operator >=(Integer a, Integer b) => a.EInteger.CompareTo(b.EInteger) >= 0;
+
+ /// Whether the first is strictly less.
public static bool operator <(Integer a, Integer b) => a.EInteger.CompareTo(b.EInteger) < 0;
+
+ /// Whether the first is less or they are equal.
public static bool operator <=(Integer a, Integer b) => a.EInteger.CompareTo(b.EInteger) <= 0;
+
+ ///
+ /// Negative, zero or positive as this is less than, equal to or greater than
+ /// , which is what sorting wants.
+ ///
+ ///
+ /// Thrown where is , rather than
+ /// sorting it first as usually would.
+ ///
public int CompareTo(Integer? other) => other is null ? throw new System.ArgumentNullException() : EInteger.CompareTo(other.EInteger);
+
+ /// Their sum, exactly and at any size.
public static Integer operator +(Integer a, Integer b) => OpSum(a, b);
+
+ /// Their difference, exactly and at any size.
public static Integer operator -(Integer a, Integer b) => OpSub(a, b);
+
+ /// Their product, exactly and at any size.
public static Integer operator *(Integer a, Integer b) => OpMul(a, b);
+
+ ///
+ /// Their quotient — not integer division. 1 / 2 is a half and not
+ /// zero, which is why the result is a : it is a
+ /// wherever the division is not exact, and
+ /// where the divisor is zero. For the truncating kind,
+ /// see .
+ ///
public static Real operator /(Integer a, Integer b) => (Real)OpDiv(a, b);
///
/// The floored remainder, which takes the sign of the divisor: -7 % 3 is 2 and
@@ -145,18 +177,44 @@ internal static bool TryParse(string s,
.IsZero || truncated.Sign == b.EInteger.Sign
? truncated
: truncated.Add(b.EInteger);
+ /// The operand itself; unary plus changes nothing.
public static Integer operator +(Integer a) => a;
+
+ /// Its negation.
public static Integer operator -(Integer a) => OpMul(MinusOne, a);
+
+ // Nothing to downcast to here, so unlike the conversions on Real and Rational
+ // these give exactly what they say.
+
+ /// The number as an .
public static implicit operator Integer(sbyte value) => Create(value);
+
+ /// The number as an .
public static implicit operator Integer(byte value) => Create(value);
+
+ /// The number as an .
public static implicit operator Integer(short value) => Create(value);
+
+ /// The number as an .
public static implicit operator Integer(ushort value) => Create(value);
+
+ /// The number as an .
public static implicit operator Integer(int value) => Create(value);
+
+ /// The number as an .
public static implicit operator Integer(uint value) => Create(value);
+
+ /// The number as an .
public static implicit operator Integer(long value) => Create(value);
+
+ /// The number as an .
public static implicit operator Integer(ulong value) => Create(value);
+
+ ///
+ /// The integer as an , of any size — this is the conversion
+ /// to reach for where a value will not fit in a .
+ ///
public static implicit operator Integer(EInteger value) => Create(value);
-#pragma warning restore CS1591
}
}
diff --git a/Sources/AngouriMath/Core/Entity/Continuous/Entity.Continuous.Operators.Classes.cs b/Sources/AngouriMath/Core/Entity/Continuous/Entity.Continuous.Operators.Classes.cs
index fe46c5258..fa216a635 100644
--- a/Sources/AngouriMath/Core/Entity/Continuous/Entity.Continuous.Operators.Classes.cs
+++ b/Sources/AngouriMath/Core/Entity/Continuous/Entity.Continuous.Operators.Classes.cs
@@ -11,7 +11,6 @@ namespace AngouriMath
{
partial record Entity
{
-#pragma warning disable CS1591 // only while records' parameters cannot be documented
///
/// A node of sum
///
@@ -34,8 +33,10 @@ private Sumf New(Entity augend, Entity addend) =>
ReferenceEquals(Augend, augend) && ReferenceEquals(Addend, addend) ? this : new(augend, addend);
internal override Priority Priority => Priority.Sum;
+ ///
public Entity NodeFirstChild => Augend;
+ ///
public Entity NodeSecondChild => Addend;
///
@@ -67,8 +68,10 @@ private Minusf New(Entity minuend, Entity subtrahend) =>
ReferenceEquals(Minuend, minuend) && ReferenceEquals(Subtrahend, subtrahend) ? this : new(minuend, subtrahend);
internal override Priority Priority => Priority.Minus;
+ ///
public Entity NodeFirstChild => Minuend;
+ ///
public Entity NodeSecondChild => Subtrahend;
///
@@ -99,8 +102,10 @@ private Mulf New(Entity multiplier, Entity multiplicand) =>
ReferenceEquals(Multiplier, multiplier) && ReferenceEquals(Multiplicand, multiplicand) ? this : new(multiplier, multiplicand);
internal override Priority Priority => Priority.Mul;
+ ///
public Entity NodeFirstChild => Multiplier;
+ ///
public Entity NodeSecondChild => Multiplicand;
///
@@ -132,8 +137,10 @@ internal Divf New(Entity dividend, Entity divisor) =>
ReferenceEquals(Dividend, dividend) && ReferenceEquals(Divisor, divisor) ? this : new(dividend, divisor);
internal override Priority Priority => Priority.Div;
+ ///
public Entity NodeFirstChild => Dividend;
+ ///
public Entity NodeSecondChild => Divisor;
///
@@ -155,8 +162,10 @@ internal Modf New(Entity dividend, Entity divisor) =>
ReferenceEquals(Dividend, dividend) && ReferenceEquals(Divisor, divisor) ? this : new(dividend, divisor);
internal override Priority Priority => Priority.Mul;
+ ///
public Entity NodeFirstChild => Dividend;
+ ///
public Entity NodeSecondChild => Divisor;
///
@@ -164,6 +173,5 @@ internal Modf New(Entity dividend, Entity divisor) =>
///
protected override Entity[] InitDirectChildren() => new[] { Dividend, Divisor };
}
-#pragma warning restore CS1591 // only while records' parameters cannot be documented
}
}
diff --git a/Sources/AngouriMath/Core/Entity/Continuous/Entity.Continuous.Rational.Definition.cs b/Sources/AngouriMath/Core/Entity/Continuous/Entity.Continuous.Rational.Definition.cs
index 92cd286db..b83d2aef3 100644
--- a/Sources/AngouriMath/Core/Entity/Continuous/Entity.Continuous.Rational.Definition.cs
+++ b/Sources/AngouriMath/Core/Entity/Continuous/Entity.Continuous.Rational.Definition.cs
@@ -48,18 +48,23 @@ private protected Rational(ERational value)
public Integer Denominator => denominator.GetValue(static @this => @this.ERational.Denominator, this);
private LazyPropertyA denominator;
-#pragma warning disable CS1591
-
+ /// Takes the ratio out, so that var (r) = rational; works.
+ /// The value as an .
public void Deconstruct(out ERational rational) => rational = ERational;
+ ///
+ /// Takes the two parts out, so that var (num, den) = rational; works.
+ /// They are in lowest terms and the denominator is positive, since that is the
+ /// only form a is ever built in.
+ ///
+ /// The numerator.
+ /// The denominator.
public void Deconstruct(out Integer numerator, out Integer denominator)
{
numerator = Numerator;
denominator = Denominator;
}
-#pragma warning restore CS1591
-
///
public override bool IsExact => true;
@@ -161,17 +166,52 @@ internal static bool TryParse(string s,
}
}
-#pragma warning disable CS1591
+ // Comparison here is on the value and answers a bool, where the same operators
+ // on Entity build an inequality node instead.
+
+ /// Whether the first is strictly greater.
public static bool operator >(Rational a, Rational b) => a.ERational.CompareTo(b.ERational) > 0;
+
+ /// Whether the first is greater or they are equal.
public static bool operator >=(Rational a, Rational b) => a.ERational.CompareTo(b.ERational) >= 0;
+
+ /// Whether the first is strictly less.
public static bool operator <(Rational a, Rational b) => a.ERational.CompareTo(b.ERational) < 0;
+
+ /// Whether the first is less or they are equal.
public static bool operator <=(Rational a, Rational b) => a.ERational.CompareTo(b.ERational) <= 0;
+
+ ///
+ /// Negative, zero or positive as this is less than, equal to or greater than
+ /// , which is what sorting wants.
+ ///
+ ///
+ /// Thrown where is , rather than
+ /// sorting it first as usually would.
+ ///
public int CompareTo(Rational? other) => other is null ? throw new System.ArgumentNullException() : ERational.CompareTo(other.ERational);
+
+ /// Their sum, exactly.
public static Rational operator +(Rational a, Rational b) => OpSum(a, b);
+
+ /// Their difference, exactly.
public static Rational operator -(Rational a, Rational b) => OpSub(a, b);
+
+ /// Their product, exactly.
public static Rational operator *(Rational a, Rational b) => OpMul(a, b);
+
+ ///
+ /// Their quotient. rather than ,
+ /// because dividing by zero has to go somewhere and the answer is
+ /// , which is not a ratio. Every other quotient of two
+ /// ratios is a ratio and arrives as one.
+ ///
public static Real operator /(Rational a, Rational b) => (Real)OpDiv(a, b);
+
+ /// The operand itself; unary plus changes nothing.
public static Rational operator +(Rational a) => a;
+
+ /// Its negation.
public static Rational operator -(Rational a) => OpMul(Integer.MinusOne, a);
///
@@ -191,26 +231,60 @@ internal static bool TryParse(string s,
.IsZero || truncated.IsNegative == b.ERational.IsNegative
? truncated
: truncated + b;
+ // As elsewhere, downcasting is on by default and a whole value arrives as an
+ // Integer, so the runtime type is narrower than the declared one.
+
+ /// The number as a .
public static implicit operator Rational(sbyte value) => (long)value;
+
+ /// The number as a .
public static implicit operator Rational(byte value) => (ulong)value;
+
+ /// The number as a .
public static implicit operator Rational(short value) => (long)value;
+
+ /// The number as a .
public static implicit operator Rational(ushort value) => (ulong)value;
+
+ /// The number as a .
public static implicit operator Rational(int value) => (long)value;
+
+ /// The number as a .
public static implicit operator Rational(uint value) => (ulong)value;
+
+ ///
+ /// The number as a — an at runtime
+ /// while downcasting is enabled.
+ ///
public static implicit operator Rational(long value)
=> MathS.Settings.DowncastingEnabled
? Integer.Create(value)
: new Rational(value);
+
+ ///
+ /// The number as a — an at runtime
+ /// while downcasting is enabled.
+ ///
public static implicit operator Rational(ulong value)
=> MathS.Settings.DowncastingEnabled
? Integer.Create(value)
: new Rational(value);
+
+ ///
+ /// The integer as a over one — an
+ /// at runtime while downcasting is enabled.
+ ///
public static implicit operator Rational(EInteger value)
=> MathS.Settings.DowncastingEnabled
? Integer.Create(value)
: new Rational(ERational.FromEInteger(value));
+
+ ///
+ /// The ratio as a , in lowest terms and with a positive
+ /// denominator: 2/4 arrives as 1/2 and 1/(-2) as
+ /// (-1)/2.
+ ///
public static implicit operator Rational(ERational value) => Create(value);
-#pragma warning restore CS1591
}
}
}
diff --git a/Sources/AngouriMath/Core/Entity/Continuous/Entity.Continuous.Real.Definition.cs b/Sources/AngouriMath/Core/Entity/Continuous/Entity.Continuous.Real.Definition.cs
index d2b4c33ab..58a99a734 100644
--- a/Sources/AngouriMath/Core/Entity/Continuous/Entity.Continuous.Real.Definition.cs
+++ b/Sources/AngouriMath/Core/Entity/Continuous/Entity.Continuous.Real.Definition.cs
@@ -110,17 +110,63 @@ internal static bool TryParse(string s,
///
public double AsDouble() => EDecimal.ToDouble();
-#pragma warning disable CS1591
+ // Comparison here is on the value and answers a bool, unlike the operators on
+ // Entity, which build an inequality node to be solved or evaluated later.
+ //
+ // These order NaN rather than refusing to: NaN sorts above every number, so
+ // NaN > 1 and NaN >= 1 are both true and 1 < NaN is true as well. That is a
+ // total order and it is not what double does, where every comparison against
+ // NaN is false. Measured at +1, -1 and NaN rather than assumed, because the
+ // IEEE habit is the one a reader arrives with.
+
+ ///
+ /// Whether the first is strictly greater. counts as greater
+ /// than every number, so NaN > x holds for any real x.
+ ///
public static bool operator >(Real a, Real b) => a.EDecimal.GreaterThan(b.EDecimal);
+
+ /// Whether the first is greater or they are equal.
public static bool operator >=(Real a, Real b) => a.EDecimal.GreaterThanOrEquals(b.EDecimal);
+
+ ///
+ /// Whether the first is strictly less. is less than nothing,
+ /// and every number is less than it.
+ ///
public static bool operator <(Real a, Real b) => a.EDecimal.LessThan(b.EDecimal);
+
+ /// Whether the first is less or they are equal.
public static bool operator <=(Real a, Real b) => a.EDecimal.LessThanOrEquals(b.EDecimal);
+
+ ///
+ /// Negative, zero or positive as this is less than, equal to or greater than
+ /// , which is what sorting wants.
+ ///
+ ///
+ /// Thrown where is . Unlike
+ /// 's usual contract, null does not sort first
+ /// here; it is refused.
+ ///
public int CompareTo(Real? other) => other is null ? throw new System.ArgumentNullException() : EDecimal.CompareTo(other.EDecimal);
+
+ /// Their sum, computed.
public static Real operator +(Real a, Real b) => OpSum(a, b);
+
+ /// Their difference, computed.
public static Real operator -(Real a, Real b) => OpSub(a, b);
+
+ /// Their product, computed.
public static Real operator *(Real a, Real b) => OpMul(a, b);
+
+ ///
+ /// Their quotient, computed. Division by zero gives rather
+ /// than throwing, so a quotient always has an answer of some kind.
+ ///
public static Real operator /(Real a, Real b) => OpDiv(a, b).Downcast();
+
+ /// The operand itself; unary plus changes nothing.
public static Real operator +(Real a) => a;
+
+ /// Its negation, computed.
public static Real operator -(Real a) => OpMul(Integer.MinusOne, a);
///
/// The floored remainder, which takes the sign of the divisor: -7 % 3 is 2 and
@@ -138,22 +184,74 @@ internal static bool TryParse(string s,
.IsZero || truncated.IsNegative == b.EDecimal.IsNegative
? truncated
: truncated.Add(b.EDecimal, MathS.Settings.DecimalPrecisionContext);
+ // With MathS.Settings.DowncastingEnabled, which is the default, a value that is
+ // exactly whole arrives as an Integer and one that is exactly a ratio as a
+ // Rational. The declared type is Real either way, so the difference is in the
+ // runtime type and in how the number prints, not in the signature.
+
+ /// The number as a .
public static implicit operator Real(sbyte value) => (long)value;
+
+ /// The number as a .
public static implicit operator Real(byte value) => (ulong)value;
+
+ /// The number as a .
public static implicit operator Real(short value) => (long)value;
+
+ /// The number as a .
public static implicit operator Real(ushort value) => (ulong)value;
+
+ /// The number as a .
public static implicit operator Real(int value) => (long)value;
+
+ /// The number as a .
public static implicit operator Real(uint value) => (ulong)value;
+
+ ///
+ /// The number as a — an at runtime
+ /// while downcasting is enabled.
+ ///
public static implicit operator Real(long value) => MathS.Settings.DowncastingEnabled ? Integer.Create(value) : new Real(value);
+
+ ///
+ /// The number as a — an at runtime
+ /// while downcasting is enabled.
+ ///
public static implicit operator Real(ulong value) => MathS.Settings.DowncastingEnabled ? Integer.Create(value) : new Real(value);
+
+ ///
+ /// The integer as a — an at runtime
+ /// while downcasting is enabled.
+ ///
public static implicit operator Real(EInteger value) => MathS.Settings.DowncastingEnabled ? Integer.Create(value) : new Real(value);
+
+ ///
+ /// The ratio as a . While downcasting is enabled it stays a
+ /// and so stays exact; with it off the ratio is evaluated
+ /// to the working precision and a third becomes a finite decimal.
+ ///
public static implicit operator Real(ERational value) => MathS.Settings.DowncastingEnabled ? Rational.Create(value) : Create(value.ToEDecimal(MathS.Settings.DecimalPrecisionContext));
+
+ /// The decimal as a .
public static implicit operator Real(EDecimal value) => Create(value);
+
+ ///
+ /// The value as a , read as the binary
+ /// it is — so 0.1f becomes the value that literal holds, not one tenth.
+ ///
public static implicit operator Real(float value) => Create(EDecimal.FromSingle(value));
+
+ ///
+ /// The value as a , read as the binary
+ /// it is rather than as the decimal it was written as.
+ ///
public static implicit operator Real(double value) => Create(EDecimal.FromDouble(value));
- public static implicit operator Real(decimal value) => Create(EDecimal.FromDecimal(value));
-#pragma warning restore CS1591
+ ///
+ /// The value as a . A is decimal
+ /// already, so this one keeps the digits that were written.
+ ///
+ public static implicit operator Real(decimal value) => Create(EDecimal.FromDecimal(value));
}
}
}
diff --git a/Sources/AngouriMath/Core/Entity/Continuous/Entity.Continuous.Rounding.Classes.cs b/Sources/AngouriMath/Core/Entity/Continuous/Entity.Continuous.Rounding.Classes.cs
index 147dcb921..b6376a30d 100644
--- a/Sources/AngouriMath/Core/Entity/Continuous/Entity.Continuous.Rounding.Classes.cs
+++ b/Sources/AngouriMath/Core/Entity/Continuous/Entity.Continuous.Rounding.Classes.cs
@@ -11,7 +11,6 @@ namespace AngouriMath
{
partial record Entity
{
-#pragma warning disable CS1591 // only while records' parameters cannot be documented
///
/// A node of round: the nearest integer, with a tie going to the even one.
///
@@ -23,6 +22,7 @@ partial record Entity
///
public sealed partial record Roundf(Entity Argument) : Function, IUnaryNode
{
+ ///
public Entity NodeChild => Argument;
private Roundf New(Entity arg) =>
@@ -46,8 +46,10 @@ private Roundf New(Entity arg) =>
///
public sealed partial record Minf(Entity Left, Entity Right) : Function, IBinaryNode
{
+ ///
public Entity NodeFirstChild => Left;
+ ///
public Entity NodeSecondChild => Right;
private Minf New(Entity left, Entity right) =>
@@ -64,8 +66,10 @@ private Minf New(Entity left, Entity right) =>
/// See for why this is a node.
public sealed partial record Maxf(Entity Left, Entity Right) : Function, IBinaryNode
{
+ ///
public Entity NodeFirstChild => Left;
+ ///
public Entity NodeSecondChild => Right;
private Maxf New(Entity left, Entity right) =>
@@ -88,8 +92,10 @@ private Maxf New(Entity left, Entity right) =>
///
public sealed partial record Gcdf(Entity Left, Entity Right) : Function, IBinaryNode
{
+ ///
public Entity NodeFirstChild => Left;
+ ///
public Entity NodeSecondChild => Right;
private Gcdf New(Entity left, Entity right) =>
@@ -99,6 +105,5 @@ private Gcdf New(Entity left, Entity right) =>
///
protected override Entity[] InitDirectChildren() => new[] { Left, Right };
}
-#pragma warning restore CS1591 // only while records' parameters cannot be documented
}
}
diff --git a/Sources/AngouriMath/Core/Entity/Continuous/Entity.Continuous.Trigonometry.Classes.cs b/Sources/AngouriMath/Core/Entity/Continuous/Entity.Continuous.Trigonometry.Classes.cs
index 16f5296d8..49b8b2ea7 100644
--- a/Sources/AngouriMath/Core/Entity/Continuous/Entity.Continuous.Trigonometry.Classes.cs
+++ b/Sources/AngouriMath/Core/Entity/Continuous/Entity.Continuous.Trigonometry.Classes.cs
@@ -11,12 +11,12 @@ namespace AngouriMath
{
partial record Entity
{
-#pragma warning disable CS1591 // only while records' parameters cannot be documented
///
/// A node of sine
///
public sealed partial record Sinf(Entity Argument) : TrigonometricFunction, IUnaryNode
{
+ ///
public Entity NodeChild => Argument;
/// Reuse the cache by returning the same object if possible
@@ -32,6 +32,7 @@ public sealed partial record Sinf(Entity Argument) : TrigonometricFunction, IUna
///
public sealed partial record Cosf(Entity Argument) : TrigonometricFunction, IUnaryNode
{
+ ///
public Entity NodeChild => Argument;
/// Reuse the cache by returning the same object if possible
@@ -47,6 +48,7 @@ public sealed partial record Cosf(Entity Argument) : TrigonometricFunction, IUna
///
public sealed partial record Tanf(Entity Argument) : TrigonometricFunction, IUnaryNode
{
+ ///
public Entity NodeChild => Argument;
/// Reuse the cache by returning the same object if possible
@@ -62,6 +64,7 @@ public sealed partial record Tanf(Entity Argument) : TrigonometricFunction, IUna
///
public sealed partial record Cotanf(Entity Argument) : TrigonometricFunction, IUnaryNode
{
+ ///
public Entity NodeChild => Argument;
/// Reuse the cache by returning the same object if possible
@@ -77,6 +80,7 @@ public sealed partial record Cotanf(Entity Argument) : TrigonometricFunction, IU
///
public sealed partial record Secantf(Entity Argument) : TrigonometricFunction, IUnaryNode
{
+ ///
public Entity NodeChild => Argument;
/// Reuse the cache by returning the same object if possible
@@ -92,6 +96,7 @@ public sealed partial record Secantf(Entity Argument) : TrigonometricFunction, I
///
public sealed partial record Cosecantf(Entity Argument) : TrigonometricFunction, IUnaryNode
{
+ ///
public Entity NodeChild => Argument;
/// Reuse the cache by returning the same object if possible
@@ -101,6 +106,5 @@ public sealed partial record Cosecantf(Entity Argument) : TrigonometricFunction,
///
protected override Entity[] InitDirectChildren() => new[] { Argument };
}
-#pragma warning restore CS1591 // only while records' parameters cannot be documented
}
}
diff --git a/Sources/AngouriMath/Core/Entity/Continuous/Number/Operators.cs b/Sources/AngouriMath/Core/Entity/Continuous/Number/Operators.cs
index 353474c3b..1244db27f 100644
--- a/Sources/AngouriMath/Core/Entity/Continuous/Number/Operators.cs
+++ b/Sources/AngouriMath/Core/Entity/Continuous/Number/Operators.cs
@@ -177,14 +177,27 @@ internal static bool AreEqual(T a, T b) where T : Number =>
(a, b) => AreEqual(a.RealPart, b.RealPart) && AreEqual(a.ImaginaryPart, b.ImaginaryPart)
);
-#pragma warning disable CS1591
+ // These compute rather than build: unlike the operators on Entity, which assemble a
+ // Sumf or a Mulf to be evaluated later, these are arithmetic on numbers and hand back
+ // the number that results.
+
+ /// Their sum, computed.
public static Number operator +(Number a, Number b) => OpSum(a, b);
+
+ /// Their difference, computed.
public static Number operator -(Number a, Number b) => OpSub(a, b);
+
+ /// Their product, computed.
public static Number operator *(Number a, Number b) => OpMul(a, b);
+
+ /// Their quotient, computed.
public static Number operator /(Number a, Number b) => OpDiv(a, b);
+
+ /// The operand itself; unary plus changes nothing.
public static Number operator +(Number a) => a;
+
+ /// Its negation, computed.
public static Number operator -(Number a) => OpMul(-1, a);
-#pragma warning restore CS1591
///
/// Gets all n-th roots of a number,
diff --git a/Sources/AngouriMath/Core/Entity/Discrete/Entity.Discrete.Classes.cs b/Sources/AngouriMath/Core/Entity/Discrete/Entity.Discrete.Classes.cs
index acbe1ce2b..e5651f2d8 100644
--- a/Sources/AngouriMath/Core/Entity/Discrete/Entity.Discrete.Classes.cs
+++ b/Sources/AngouriMath/Core/Entity/Discrete/Entity.Discrete.Classes.cs
@@ -12,7 +12,6 @@ namespace AngouriMath
{
partial record Entity
{
-#pragma warning disable CS1591 // TODO: it's only for records' parameters! Remove it once you can document records parameters
///
/// This node represents all possible values a boolean node might be of
@@ -95,6 +94,7 @@ public sealed partial record Notf(Entity Argument) : Statement, IUnaryNode
{
internal override Priority Priority => Priority.Negation;
+ ///
public Entity NodeChild => Argument;
private Notf New(Entity negated) =>
@@ -113,8 +113,10 @@ public sealed partial record Andf(Entity Left, Entity Right) : Statement, IBinar
{
internal override Priority Priority => Priority.Conjunction;
+ ///
public Entity NodeFirstChild => Left;
+ ///
public Entity NodeSecondChild => Right;
private Andf New(Entity left, Entity right) =>
@@ -133,8 +135,10 @@ public sealed partial record Orf(Entity Left, Entity Right) : Statement, IBinary
{
internal override Priority Priority => Priority.Disjunction;
+ ///
public Entity NodeFirstChild => Left;
+ ///
public Entity NodeSecondChild => Right;
private Orf New(Entity left, Entity right) =>
@@ -153,8 +157,10 @@ public sealed partial record Xorf(Entity Left, Entity Right) : Statement, IBinar
{
internal override Priority Priority => Priority.XDisjunction;
+ ///
public Entity NodeFirstChild => Left;
+ ///
public Entity NodeSecondChild => Right;
private Xorf New(Entity left, Entity right) =>
@@ -173,8 +179,10 @@ public sealed partial record Impliesf(Entity Assumption, Entity Conclusion) : St
{
internal override Priority Priority => Priority.Implication;
+ ///
public Entity NodeFirstChild => Assumption;
+ ///
public Entity NodeSecondChild => Conclusion;
private Impliesf New(Entity assumption, Entity conclusion) =>
@@ -197,8 +205,10 @@ public sealed partial record Equalsf(Entity Left, Entity Right) : ComparisonSign
{
internal override Priority Priority => Priority.Equal;
+ ///
public Entity NodeFirstChild => Left;
+ ///
public Entity NodeSecondChild => Right;
internal Equalsf New(Entity left, Entity right)
@@ -221,8 +231,10 @@ public sealed partial record Greaterf(Entity Left, Entity Right) : ComparisonSig
{
internal override Priority Priority => Priority.GreaterThan;
+ ///
public Entity NodeFirstChild => Left;
+ ///
public Entity NodeSecondChild => Right;
internal Greaterf New(Entity left, Entity right)
@@ -245,8 +257,10 @@ public sealed partial record GreaterOrEqualf(Entity Left, Entity Right) : Compar
{
internal override Priority Priority => Priority.GreaterThan;
+ ///
public Entity NodeFirstChild => Left;
+ ///
public Entity NodeSecondChild => Right;
internal GreaterOrEqualf New(Entity left, Entity right)
@@ -269,8 +283,10 @@ public sealed partial record Lessf(Entity Left, Entity Right) : ComparisonSign,
{
internal override Priority Priority => Priority.GreaterThan;
+ ///
public Entity NodeFirstChild => Left;
+ ///
public Entity NodeSecondChild => Right;
internal Lessf New(Entity left, Entity right)
@@ -293,8 +309,10 @@ public sealed partial record LessOrEqualf(Entity Left, Entity Right) : Compariso
{
internal override Priority Priority => Priority.GreaterThan;
+ ///
public Entity NodeFirstChild => Left;
+ ///
public Entity NodeSecondChild => Right;
internal LessOrEqualf New(Entity left, Entity right)
@@ -318,8 +336,10 @@ public sealed partial record Inf(Entity Element, Entity SupSet) : Statement, IBi
{
internal override Priority Priority => Priority.ContainsIn;
+ ///
public Entity NodeFirstChild => Element;
+ ///
public Entity NodeSecondChild => SupSet;
internal Inf New(Entity element, Entity supSet)
@@ -339,6 +359,7 @@ public override Entity Replace(Func func)
///
public sealed partial record Phif(Entity Argument) : Function, IUnaryNode
{
+ ///
public Entity NodeChild => Argument;
internal Phif New(Entity argument)
@@ -352,6 +373,5 @@ internal Phif New(Entity argument)
}
#endregion
-#pragma warning restore CS1591 // TODO: it's only for records' parameters! Remove it once you can document records parameters
}
}
diff --git a/Sources/AngouriMath/Core/Entity/Entity.ImplicitOperators.cs b/Sources/AngouriMath/Core/Entity/Entity.ImplicitOperators.cs
index 9f78dcc67..d0c44e4b6 100644
--- a/Sources/AngouriMath/Core/Entity/Entity.ImplicitOperators.cs
+++ b/Sources/AngouriMath/Core/Entity/Entity.ImplicitOperators.cs
@@ -11,25 +11,76 @@ namespace AngouriMath
{
partial record Entity
{
-#pragma warning disable CS1591
+ // A number written where an expression is expected becomes a literal node of the
+ // narrowest kind that holds it exactly: the integral types become Integer, a ratio
+ // becomes Rational, and the rest become Real. This is what lets `x + 1` and
+ // `MathS.Sin(2)` be written at all.
+
+ /// The number as an literal.
public static implicit operator Entity(sbyte value) => Number.Integer.Create(value);
+
+ /// The number as an literal.
public static implicit operator Entity(byte value) => Number.Integer.Create(value);
+
+ /// The number as an literal.
public static implicit operator Entity(short value) => Number.Integer.Create(value);
+
+ /// The number as an literal.
public static implicit operator Entity(ushort value) => Number.Integer.Create(value);
+
+ /// The number as an literal.
public static implicit operator Entity(int value) => Number.Integer.Create(value);
+
+ /// The number as an literal.
public static implicit operator Entity(uint value) => Number.Integer.Create(value);
+
+ /// The number as an literal.
public static implicit operator Entity(long value) => Number.Integer.Create(value);
+
+ /// The number as an literal.
public static implicit operator Entity(ulong value) => Number.Integer.Create(value);
+
+ ///
+ /// The integer as an literal, of any size — this is the
+ /// conversion to reach for where a value will not fit in a .
+ ///
public static implicit operator Entity(EInteger value) => Number.Integer.Create(value);
+
+ /// The ratio as a literal, exactly.
public static implicit operator Entity(ERational value) => Number.Rational.Create(value);
+
+ /// The decimal as a literal.
public static implicit operator Entity(EDecimal value) => Number.Real.Create(value);
+
+ ///
+ /// The value as a literal, read as the binary
+ /// it is — so 0.1f becomes the value that literal holds
+ /// and not one tenth. Write 0.1m, or a , for the exact
+ /// number.
+ ///
public static implicit operator Entity(float value) => Number.Real.Create(EDecimal.FromSingle(value));
+
+ ///
+ /// The value as a literal, read as the binary
+ /// it is rather than as the decimal it was written as.
+ ///
public static implicit operator Entity(double value) => Number.Real.Create(EDecimal.FromDouble(value));
+
+ ///
+ /// The value as a literal. A is
+ /// decimal already, so this one keeps the digits that were written.
+ ///
public static implicit operator Entity(decimal value) => Number.Real.Create(EDecimal.FromDecimal(value));
+
+ ///
+ /// The .NET complex number as a literal, through its two
+ /// parts and their precision.
+ ///
public static implicit operator Entity(System.Numerics.Complex value) =>
Number.Complex.Create(EDecimal.FromDouble(value.Real), EDecimal.FromDouble(value.Imaginary));
+
+ /// The big integer as an literal, exactly.
public static implicit operator Entity(System.Numerics.BigInteger bigInt)
=> Number.Integer.Create(EInteger.FromBytes(bigInt.ToByteArray(), littleEndian: true));
-#pragma warning restore CS1591
}
}
diff --git a/Sources/AngouriMath/Core/Entity/Omni/Entity.Matrix.cs b/Sources/AngouriMath/Core/Entity/Omni/Entity.Matrix.cs
index 5fd80908f..c8f2ec06a 100644
--- a/Sources/AngouriMath/Core/Entity/Omni/Entity.Matrix.cs
+++ b/Sources/AngouriMath/Core/Entity/Omni/Entity.Matrix.cs
@@ -71,35 +71,83 @@ internal Matrix Elementwise(Matrix other, Func operation
///
protected override Entity[] InitDirectChildren() => InnerMatrix.Iterate().Select(tup => tup.Value).ToArray();
-#pragma warning disable CS1591
+ ///
+ /// Arithmetic on as the tensor library wants it, so that a
+ /// matrix can hold expressions rather than numbers.
+ ///
+ ///
+ /// Every operation here normalises its result with .
+ /// Without it an entry would accumulate the whole history of the operations that
+ /// built it — a determinant over a 4×4 of symbols is a sum of products of sums, and
+ /// left unnormalised it grows past being readable or comparable.
+ ///
public readonly struct EntityTensorWrapperOperations : IOperations
{
+ /// Their sum, normalised.
public Entity Add(Entity a, Entity b) => (a + b).InnerSimplified;
+
+ /// Their difference, normalised.
public Entity Subtract(Entity a, Entity b) => (a - b).InnerSimplified;
+
+ /// Their product, normalised.
public Entity Multiply(Entity a, Entity b) => (a * b).InnerSimplified;
+
+ /// Its negation, normalised.
public Entity Negate(Entity a) => (-a).InnerSimplified;
+
+ /// Their quotient, normalised.
public Entity Divide(Entity a, Entity b) => (a / b).InnerSimplified;
+
+ /// The multiplicative identity, which is the integer one.
public Entity CreateOne() => Number.Integer.One;
+
+ /// The additive identity, which is the integer zero.
public Entity CreateZero() => Number.Integer.Zero;
+
+ ///
+ /// The entity itself. An is immutable, so there is nothing
+ /// to copy and sharing it is safe.
+ ///
public Entity Copy(Entity a) => a;
+
#pragma warning disable CA1822 // Mark members as static
+ /// The entity itself, as the interface requires it be passed through.
public Entity Forward(Entity a) => a;
#pragma warning restore CA1822 // Mark members as static
+
+ ///
+ /// Whether the two are the same expression. This is structural equality and not
+ /// mathematical: x + x and 2 * x are not equal here.
+ ///
public bool AreEqual(Entity a, Entity b) => a == b;
+
+ ///
+ /// Whether the entity is the literal zero — again structurally, so an expression
+ /// that happens to be zero everywhere is not recognised as one.
+ ///
public bool IsZero(Entity a) => a == 0;
+
+ /// The entity written out, as writes it.
public string ToString(Entity a) => a.Stringize();
+ ///
+ /// Not supported: an expression has no byte form here.
+ ///
+ /// Always.
public byte[] Serialize(Entity a)
{
throw new NotSufficientlySupportedException("Serializing a matrix is not supported");
}
+ ///
+ /// Not supported: an expression has no byte form here.
+ ///
+ /// Always.
public Entity Deserialize(byte[] data)
{
throw new NotSufficientlySupportedException("Deserializing a matrix is not supported");
}
}
-#pragma warning restore CS1591
///
/// The number of columns of a matrix. It is 1 for vectors.
///
diff --git a/Sources/AngouriMath/Core/Entity/Omni/Entity.Omni.Classes.cs b/Sources/AngouriMath/Core/Entity/Omni/Entity.Omni.Classes.cs
index aa8b53c21..e5ae575be 100644
--- a/Sources/AngouriMath/Core/Entity/Omni/Entity.Omni.Classes.cs
+++ b/Sources/AngouriMath/Core/Entity/Omni/Entity.Omni.Classes.cs
@@ -222,7 +222,6 @@ public bool TryIsSubsetOf(FiniteSet superSet, out bool isSub)
}
#endregion
-#pragma warning disable CS1591 // TODO: it's only for records' parameters! Remove it once you can document records parameters
#region Interval
///
@@ -810,7 +809,6 @@ public override Set Filter(Entity predicate, Variable over)
}
#endregion
}
-#pragma warning restore CS1591 // TODO: it's only for records' parameters! Remove it once you can document records parameters
///
/// Application of arguments to the given expression
diff --git a/Sources/AngouriMath/Core/Entity/Omni/Entity.Piecewise.cs b/Sources/AngouriMath/Core/Entity/Omni/Entity.Piecewise.cs
index aef56b10b..94cbd5c3e 100644
--- a/Sources/AngouriMath/Core/Entity/Omni/Entity.Piecewise.cs
+++ b/Sources/AngouriMath/Core/Entity/Omni/Entity.Piecewise.cs
@@ -14,13 +14,14 @@ namespace AngouriMath
{
partial record Entity
{
-#pragma warning disable CS1591 // TODO: add docs for records' arguments
///
/// That is a node which equals Expression if Predicate is true, otherwise
///
public sealed partial record Providedf(Entity Expression, Entity Predicate) : Entity, IBinaryNode
{
+ ///
public Entity NodeFirstChild => Expression;
+ ///
public Entity NodeSecondChild => Predicate;
internal Providedf New(Entity expression, Entity predicate)
@@ -50,6 +51,10 @@ public override Entity Replace(Func func)
///
public sealed partial record Piecewise : Entity, IEquatable
{
+ ///
+ /// The cases, in the order they are considered: the value of the piecewise is that
+ /// of the first one whose condition holds.
+ ///
public IEnumerable Cases => cases;
private readonly IEnumerable cases = Enumerable.Empty();
@@ -113,7 +118,6 @@ public Piecewise ApplyToValues(Func transformation)
=> Cases.Select(c => c.New(transformation(c.Expression), c.Predicate)).ToPiecewise();
}
-#pragma warning restore CS1591 // Missing XML comment for publicly visible type or member
}
diff --git a/Sources/AngouriMath/Core/Entity/Omni/Entity.Set.cs b/Sources/AngouriMath/Core/Entity/Omni/Entity.Set.cs
index 0b52c47cb..377a4c073 100644
--- a/Sources/AngouriMath/Core/Entity/Omni/Entity.Set.cs
+++ b/Sources/AngouriMath/Core/Entity/Omni/Entity.Set.cs
@@ -79,9 +79,11 @@ public bool Contains(Entity entity)
/// A new node
public Set SetSubtract(Entity anotherSet) => new SetMinusf(this, anotherSet);
-#pragma warning disable CS1591
+ ///
+ /// The domain as the set of all its values — becomes the set
+ /// of reals — so a domain can be written wherever an expression is expected.
+ ///
public static implicit operator Entity(Domain domain) => Set.SpecialSet.Create(domain);
-#pragma warning restore CS1591
}
}
diff --git a/Sources/Tests/UnitTests/Core/RealComparisonTest.cs b/Sources/Tests/UnitTests/Core/RealComparisonTest.cs
new file mode 100644
index 000000000..afb1656b8
--- /dev/null
+++ b/Sources/Tests/UnitTests/Core/RealComparisonTest.cs
@@ -0,0 +1,66 @@
+//
+// Copyright (c) 2019-2026 Angouri.
+// AngouriMath is licensed under MIT.
+// Details: https://github.com/asc-community/AngouriMath/blob/master/LICENSE.md.
+// Website: https://am.angouri.org.
+//
+
+using AngouriMath;
+using Xunit;
+using static AngouriMath.Entity.Number;
+
+namespace AngouriMath.Tests.Core
+{
+ ///
+ /// How 's comparison operators order , which is not
+ /// how does and is now written into their documentation.
+ ///
+ ///
+ /// Pinned because it is surprising and because the documentation asserts it. A reader
+ /// arrives with the IEEE habit, where every comparison against NaN is false; here the
+ /// comparison is a total order and NaN sits at the top of it.
+ ///
+ [Trait("Area", "Core")]
+ public sealed class RealComparisonTest
+ {
+ [Theory]
+ [InlineData(1)]
+ [InlineData(-1)]
+ [InlineData(0)]
+ [InlineData(100000)]
+ public void NaNIsAboveEveryNumber(int number)
+ {
+ Real value = number;
+ Assert.True(Real.NaN > value);
+ Assert.True(Real.NaN >= value);
+ Assert.False(Real.NaN < value);
+ Assert.False(Real.NaN <= value);
+
+ Assert.True(value < Real.NaN);
+ Assert.False(value > Real.NaN);
+ }
+
+ /// And the ordinary order is the ordinary one.
+ [Fact]
+ public void AndTheRestOrdersAsExpected()
+ {
+ Real one = 1, two = 2;
+ Assert.True(two > one);
+ Assert.True(one < two);
+ Assert.True(one <= one);
+ Assert.True(one >= one);
+ Assert.False(one > one);
+ }
+
+ ///
+ /// Division by zero answers rather than throwing, so a quotient
+ /// always has an answer of some kind.
+ ///
+ [Fact]
+ public void DivisionByZeroIsNaNRatherThanAThrow()
+ {
+ Real one = 1, zero = 0;
+ Assert.True((one / zero).IsNaN);
+ }
+ }
+}