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
19 changes: 19 additions & 0 deletions BREAKING-CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,25 @@ read first.
| **Silent** | `"1/x".Integrate("x")`, and every antiderivative with a logarithm | `ln(abs(x)) + C` | `ln(x) + C` |
| **Silent** | `CostModel.FewestDivisions.Cost(y ^ (1 * (-1)) * x)` | `0.007`, cheaper than `x / y` | `1.007` |
| **Silent** | `Real.NaN > (Real)1`, and the other three operators | `true` | `false` |
| **Silent** | a rewritten expression under `domain(...)` — including via `Substitute` | the constraint was dropped, so it answered | it refuses, as it did before the rewrite |

### A rewritten node keeps its `Codomain`, so a domain constraint no longer disappears

`Entity.Replace` rebuilds every node on the path to a change, and a rebuilt node started from its
type's default codomain rather than the one the original carried. Any rewrite therefore dropped a
`domain(...)` annotation — including `Substitute`, which is built on `Replace`.

```csharp
"domain(sqrt(x), ZZ)".ToEntity().Substitute("x", "4/9".ToEntity()).EvalNumerical()
// was: 2/3 now: NaN — 2/3 is not an integer, so the constraint refuses it
```

The old behaviour was **silent** and one-sided: constraints were only ever weakened, never
strengthened, so a rewrite could make an undefined expression look defined but never the reverse.
An expression that answered a value where it should have refused now refuses.

Measured: the whole suite passes unchanged with the fix in, so nothing in the library depended on
the annotation being lost. [#955](https://github.com/asc-community/AngouriMath/issues/955).

### `Real`'s comparison operators refuse `NaN` instead of ordering it

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public sealed partial record Signumf(Entity Argument) : Function, IUnaryNode
public Entity NodeChild => Argument;

private Signumf New(Entity arg) =>
ReferenceEquals(Argument, arg) ? this : new(arg);
ReferenceEquals(Argument, arg) ? this : new(arg) { Codomain = Codomain };
/// <inheritdoc/>
public override Entity Replace(Func<Entity, Entity> func) => func(New(Argument.Replace(func)));
/// <inheritdoc/>
Expand All @@ -36,7 +36,7 @@ public sealed partial record Absf(Entity Argument) : Function, IUnaryNode
public Entity NodeChild => Argument;

private Absf New(Entity arg) =>
ReferenceEquals(Argument, arg) ? this : new(arg);
ReferenceEquals(Argument, arg) ? this : new(arg) { Codomain = Codomain };
/// <inheritdoc/>
public override Entity Replace(Func<Entity, Entity> func) => func(New(Argument.Replace(func)));
/// <inheritdoc/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public sealed partial record Arcsinf(Entity Argument) : TrigonometricFunction, I
public Entity NodeChild => Argument;

/// <summary>Reuse the cache by returning the same object if possible</summary>
private Arcsinf New(Entity argument) => ReferenceEquals(Argument, argument) ? this : new(argument);
private Arcsinf New(Entity argument) => ReferenceEquals(Argument, argument) ? this : new(argument) { Codomain = Codomain };
/// <inheritdoc/>
public override Entity Replace(Func<Entity, Entity> func) => func(New(Argument.Replace(func)));
/// <inheritdoc/>
Expand All @@ -36,7 +36,7 @@ public sealed partial record Arccosf(Entity Argument) : TrigonometricFunction, I
public Entity NodeChild => Argument;

/// <summary>Reuse the cache by returning the same object if possible</summary>
private Arccosf New(Entity argument) => ReferenceEquals(Argument, argument) ? this : new(argument);
private Arccosf New(Entity argument) => ReferenceEquals(Argument, argument) ? this : new(argument) { Codomain = Codomain };
/// <inheritdoc/>
public override Entity Replace(Func<Entity, Entity> func) => func(New(Argument.Replace(func)));
/// <inheritdoc/>
Expand All @@ -52,7 +52,7 @@ public sealed partial record Arctanf(Entity Argument) : TrigonometricFunction, I
public Entity NodeChild => Argument;

/// <summary>Reuse the cache by returning the same object if possible</summary>
private Arctanf New(Entity argument) => ReferenceEquals(Argument, argument) ? this : new(argument);
private Arctanf New(Entity argument) => ReferenceEquals(Argument, argument) ? this : new(argument) { Codomain = Codomain };
/// <inheritdoc/>
public override Entity Replace(Func<Entity, Entity> func) => func(New(Argument.Replace(func)));
/// <inheritdoc/>
Expand All @@ -68,7 +68,7 @@ public sealed partial record Arccotanf(Entity Argument) : TrigonometricFunction,
public Entity NodeChild => Argument;

/// <summary>Reuse the cache by returning the same object if possible</summary>
Arccotanf New(Entity argument) => ReferenceEquals(Argument, argument) ? this : new(argument);
Arccotanf New(Entity argument) => ReferenceEquals(Argument, argument) ? this : new(argument) { Codomain = Codomain };
/// <inheritdoc/>
public override Entity Replace(Func<Entity, Entity> func) => func(New(Argument.Replace(func)));
/// <inheritdoc/>
Expand All @@ -84,7 +84,7 @@ public sealed partial record Arcsecantf(Entity Argument) : TrigonometricFunction
public Entity NodeChild => Argument;

/// <summary>Reuse the cache by returning the same object if possible</summary>
private Arcsecantf New(Entity argument) => ReferenceEquals(Argument, argument) ? this : new(argument);
private Arcsecantf New(Entity argument) => ReferenceEquals(Argument, argument) ? this : new(argument) { Codomain = Codomain };
/// <inheritdoc/>
public override Entity Replace(Func<Entity, Entity> func) => func(New(Argument.Replace(func)));
/// <inheritdoc/>
Expand All @@ -100,7 +100,7 @@ public sealed partial record Arccosecantf(Entity Argument) : TrigonometricFuncti
public Entity NodeChild => Argument;

/// <summary>Reuse the cache by returning the same object if possible</summary>
private Arccosecantf New(Entity argument) => ReferenceEquals(Argument, argument) ? this : new(argument);
private Arccosecantf New(Entity argument) => ReferenceEquals(Argument, argument) ? this : new(argument) { Codomain = Codomain };
/// <inheritdoc/>
public override Entity Replace(Func<Entity, Entity> func) => func(New(Argument.Replace(func)));
/// <inheritdoc/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public sealed partial record Derivativef(Entity Expression, Entity Var, int Iter
/// <summary>Reuse the cache by returning the same object if possible</summary>
private Derivativef New(Entity expression, Entity var) =>
ReferenceEquals(Expression, expression) && ReferenceEquals(Var, var)
? this : new(expression, var, Iterations);
? this : new(expression, var, Iterations) { Codomain = Codomain };
/// <inheritdoc/>
public override Entity Replace(Func<Entity, Entity> func) =>
func(New(Expression.Replace(func), Var.Replace(func)));
Expand All @@ -40,7 +40,7 @@ private Integralf New(Entity expression, Entity var, (Entity from, Entity to)? r
ReferenceEquals(Expression, expression) && ReferenceEquals(Var, var)
&& (range is null && Range is null || range is var (newFrom, newTo) && Range is var (oldFrom, oldTo)
&& ReferenceEquals(newFrom, oldFrom) && ReferenceEquals(newTo, oldTo))
? this : new(expression, var, range);
? this : new(expression, var, range) { Codomain = Codomain };
/// <inheritdoc/>
public override Entity Replace(Func<Entity, Entity> func) =>
func(New(Expression.Replace(func), Var, Range is var (from, to) ? (from.Replace(func), to.Replace(func)) : null));
Expand All @@ -56,7 +56,7 @@ public sealed partial record Limitf(Entity Expression, Entity Var, Entity Destin
/// <summary>Reuse the cache by returning the same object if possible</summary>
private Limitf New(Entity expression, Entity var, Entity destination, ApproachFrom approachFrom) =>
ReferenceEquals(Expression, expression) && ReferenceEquals(Var, var) && ReferenceEquals(Destination, destination)
&& ApproachFrom == approachFrom ? this : new(expression, var, destination, approachFrom);
&& ApproachFrom == approachFrom ? this : new(expression, var, destination, approachFrom) { Codomain = Codomain };
/// <inheritdoc/>
public override Entity Replace(Func<Entity, Entity> func) =>
func(New(Expression.Replace(func), Var.Replace(func), Destination.Replace(func), ApproachFrom));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public sealed partial record Powf(Entity Base, Entity Exponent) : Function, IBin
{
/// <summary>Reuse the cache by returning the same object if possible</summary>
private Powf New(Entity @base, Entity exponent) =>
ReferenceEquals(Base, @base) && ReferenceEquals(Exponent, exponent) ? this : new(@base, exponent);
ReferenceEquals(Base, @base) && ReferenceEquals(Exponent, exponent) ? this : new(@base, exponent) { Codomain = Codomain };
internal override Priority Priority => Priority.Pow;

/// <inheritdoc/>
Expand All @@ -40,7 +40,7 @@ public sealed partial record Logf(Entity Base, Entity Antilogarithm) : Function,
{
/// <summary>Reuse the cache by returning the same object if possible</summary>
private Logf New(Entity @base, Entity antilogarithm) =>
ReferenceEquals(Base, @base) && ReferenceEquals(Antilogarithm, antilogarithm) ? this : new(@base, antilogarithm);
ReferenceEquals(Base, @base) && ReferenceEquals(Antilogarithm, antilogarithm) ? this : new(@base, antilogarithm) { Codomain = Codomain };

/// <inheritdoc/>
public Entity NodeFirstChild => Base;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ partial record Entity
public sealed partial record Factorialf(Entity Argument) : Function, IUnaryNode
{
/// <summary>Reuse the cache by returning the same object if possible</summary>
private Factorialf New(Entity argument) => ReferenceEquals(Argument, argument) ? this : new(argument);
private Factorialf New(Entity argument) => ReferenceEquals(Argument, argument) ? this : new(argument) { Codomain = Codomain };
// This is still a function for pattern replacement
internal override Priority Priority => Priority.Factorial;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//
//
// Copyright (c) 2019-2026 Angouri.
// AngouriMath is licensed under MIT.
// Details: https://github.com/asc-community/AngouriMath/blob/master/LICENSE.md.
Expand Down Expand Up @@ -26,7 +26,7 @@ public sealed partial record Floorf(Entity Argument) : Function, IUnaryNode
public Entity NodeChild => Argument;

private Floorf New(Entity arg) =>
ReferenceEquals(Argument, arg) ? this : new(arg);
ReferenceEquals(Argument, arg) ? this : new(arg) { Codomain = Codomain };
/// <inheritdoc/>
public override Entity Replace(Func<Entity, Entity> func) => func(New(Argument.Replace(func)));
/// <inheritdoc/>
Expand All @@ -46,7 +46,7 @@ public sealed partial record Ceilf(Entity Argument) : Function, IUnaryNode
public Entity NodeChild => Argument;

private Ceilf New(Entity arg) =>
ReferenceEquals(Argument, arg) ? this : new(arg);
ReferenceEquals(Argument, arg) ? this : new(arg) { Codomain = Codomain };
/// <inheritdoc/>
public override Entity Replace(Func<Entity, Entity> func) => func(New(Argument.Replace(func)));
/// <inheritdoc/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public static Entity Sum(IEnumerable<Entity> terms)

/// <summary>Reuse the cache by returning the same object if possible</summary>
private Sumf New(Entity augend, Entity addend) =>
ReferenceEquals(Augend, augend) && ReferenceEquals(Addend, addend) ? this : new(augend, addend);
ReferenceEquals(Augend, augend) && ReferenceEquals(Addend, addend) ? this : new(augend, addend) { Codomain = Codomain };
internal override Priority Priority => Priority.Sum;

/// <inheritdoc/>
Expand Down Expand Up @@ -65,7 +65,7 @@ public sealed partial record Minusf(Entity Minuend, Entity Subtrahend) : Continu
{
/// <summary>Reuse the cache by returning the same object if possible</summary>
private Minusf New(Entity minuend, Entity subtrahend) =>
ReferenceEquals(Minuend, minuend) && ReferenceEquals(Subtrahend, subtrahend) ? this : new(minuend, subtrahend);
ReferenceEquals(Minuend, minuend) && ReferenceEquals(Subtrahend, subtrahend) ? this : new(minuend, subtrahend) { Codomain = Codomain };
internal override Priority Priority => Priority.Minus;

/// <inheritdoc/>
Expand Down Expand Up @@ -99,7 +99,7 @@ public static Entity Multiply(IEnumerable<Entity> terms)

/// <summary>Reuse the cache by returning the same object if possible</summary>
private Mulf New(Entity multiplier, Entity multiplicand) =>
ReferenceEquals(Multiplier, multiplier) && ReferenceEquals(Multiplicand, multiplicand) ? this : new(multiplier, multiplicand);
ReferenceEquals(Multiplier, multiplier) && ReferenceEquals(Multiplicand, multiplicand) ? this : new(multiplier, multiplicand) { Codomain = Codomain };
internal override Priority Priority => Priority.Mul;

/// <inheritdoc/>
Expand Down Expand Up @@ -134,7 +134,7 @@ public sealed partial record Divf(Entity Dividend, Entity Divisor) : ContinuousN
{
/// <summary>Reuse the cache by returning the same object if possible</summary>
internal Divf New(Entity dividend, Entity divisor) =>
ReferenceEquals(Dividend, dividend) && ReferenceEquals(Divisor, divisor) ? this : new(dividend, divisor);
ReferenceEquals(Dividend, dividend) && ReferenceEquals(Divisor, divisor) ? this : new(dividend, divisor) { Codomain = Codomain };
internal override Priority Priority => Priority.Div;

/// <inheritdoc/>
Expand All @@ -159,7 +159,7 @@ public sealed partial record Modf(Entity Dividend, Entity Divisor) : ContinuousN
{
/// <summary>Reuse the cache by returning the same object if possible</summary>
internal Modf New(Entity dividend, Entity divisor) =>
ReferenceEquals(Dividend, dividend) && ReferenceEquals(Divisor, divisor) ? this : new(dividend, divisor);
ReferenceEquals(Dividend, dividend) && ReferenceEquals(Divisor, divisor) ? this : new(dividend, divisor) { Codomain = Codomain };
internal override Priority Priority => Priority.Mul;

/// <inheritdoc/>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//
//
// Copyright (c) 2019-2026 Angouri.
// AngouriMath is licensed under MIT.
// Details: https://github.com/asc-community/AngouriMath/blob/master/LICENSE.md.
Expand Down Expand Up @@ -26,7 +26,7 @@ public sealed partial record Roundf(Entity Argument) : Function, IUnaryNode
public Entity NodeChild => Argument;

private Roundf New(Entity arg) =>
ReferenceEquals(Argument, arg) ? this : new(arg);
ReferenceEquals(Argument, arg) ? this : new(arg) { Codomain = Codomain };
/// <inheritdoc/>
public override Entity Replace(Func<Entity, Entity> func) => func(New(Argument.Replace(func)));
/// <inheritdoc/>
Expand All @@ -53,7 +53,7 @@ public sealed partial record Minf(Entity Left, Entity Right) : Function, IBinary
public Entity NodeSecondChild => Right;

private Minf New(Entity left, Entity right) =>
ReferenceEquals(Left, left) && ReferenceEquals(Right, right) ? this : new(left, right);
ReferenceEquals(Left, left) && ReferenceEquals(Right, right) ? this : new(left, right) { Codomain = Codomain };
/// <inheritdoc/>
public override Entity Replace(Func<Entity, Entity> func) => func(New(Left.Replace(func), Right.Replace(func)));
/// <inheritdoc/>
Expand All @@ -73,7 +73,7 @@ public sealed partial record Maxf(Entity Left, Entity Right) : Function, IBinary
public Entity NodeSecondChild => Right;

private Maxf New(Entity left, Entity right) =>
ReferenceEquals(Left, left) && ReferenceEquals(Right, right) ? this : new(left, right);
ReferenceEquals(Left, left) && ReferenceEquals(Right, right) ? this : new(left, right) { Codomain = Codomain };
/// <inheritdoc/>
public override Entity Replace(Func<Entity, Entity> func) => func(New(Left.Replace(func), Right.Replace(func)));
/// <inheritdoc/>
Expand All @@ -99,7 +99,7 @@ public sealed partial record Gcdf(Entity Left, Entity Right) : Function, IBinary
public Entity NodeSecondChild => Right;

private Gcdf New(Entity left, Entity right) =>
ReferenceEquals(Left, left) && ReferenceEquals(Right, right) ? this : new(left, right);
ReferenceEquals(Left, left) && ReferenceEquals(Right, right) ? this : new(left, right) { Codomain = Codomain };
/// <inheritdoc/>
public override Entity Replace(Func<Entity, Entity> func) => func(New(Left.Replace(func), Right.Replace(func)));
/// <inheritdoc/>
Expand Down
Loading
Loading