diff --git a/src/Symbolics/Expression.fs b/src/Symbolics/Expression.fs index e64af89..766857e 100644 --- a/src/Symbolics/Expression.fs +++ b/src/Symbolics/Expression.fs @@ -298,6 +298,7 @@ module Operators = | x -> Product (List.rev x) /// Multiply a number with an expression (potentially a denormalized product) + /// Intentionally distribte -1, e.g. -(a + b) = -a - b let rec valueMul (v:Value) x = if Value.isZero v then zero else match x with @@ -306,6 +307,9 @@ module Operators = | Product [a] -> if Value.isOne v then a else Product [Values.unpack v; a] | Product ((Values.Value a)::ax) -> valueMul (Value.product (a,v)) (Product ax) | Product ax -> if Value.isOne v then x else Product (Values.unpack v::ax) + | Sum ax as x'-> if Value.isOne v then x' + else if Value.isMinusOne v then ax |> List.map (function xi -> valueMul v xi) |> Sum + else Product [Values.unpack v; x'] | x -> if Value.isOne v then x else Product [Values.unpack v; x] match x, y with diff --git a/src/SymbolicsUnitTests/Operators/Exponential.fs b/src/SymbolicsUnitTests/Operators/Exponential.fs index 473e118..81013e8 100644 --- a/src/SymbolicsUnitTests/Operators/Exponential.fs +++ b/src/SymbolicsUnitTests/Operators/Exponential.fs @@ -18,7 +18,7 @@ let tests = } test "Special Values" { - exp(x + y - (x + y)) ==> "exp(x + y - (x + y))" // "1" + exp(x + y - (x + y)) ==> "1" exp(-1Q) ==> "1/e" exp(1Q/2Q*pi*Constant I) ==> "j" diff --git a/src/SymbolicsUnitTests/Tests.fs b/src/SymbolicsUnitTests/Tests.fs index a4ee20f..1bc4dd2 100644 --- a/src/SymbolicsUnitTests/Tests.fs +++ b/src/SymbolicsUnitTests/Tests.fs @@ -237,12 +237,13 @@ let tests = test "Algebraic Expansion" { - // Auto-simplification does not expand expressions: - (a+b)-(a+b) ==> "a + b - (a + b)" + // Auto-simplification does not expand expressions, but -1 distributes inside parentheses: + (a+b)-(a+b) ==> "0" (a+b)-(a+b) |> Algebraic.expand ==> "0" - 2*(a+b)-(a+b) ==> "a + b" + 2*(a+b)-(a+b) ==> "-a - b + 2*(a + b)" (a+b)-2*(a+b) |> Algebraic.expand ===> "(-1)*a + (-1)*b" (a+b)-2*(a+b) |> Algebraic.expand ==> "-a - b" + -(a + b) + 2*(a + b) ==> "-a - b + 2*(a + b)" (a*b)/(b*a) ==> "1" (a*b)**2/(b*a) ==> "a*b" @@ -285,7 +286,7 @@ let tests = test "Algebaric Operators" { - negate (x + y**2) ==> "-(x + y^2)" + negate (x + y**2) ==> "-x - y^2" Algebraic.factors (b*cos(x)*ln(d)*x) ==+> ["b"; "x"; "ln(d)"; "cos(x)"] Algebraic.factors (b*cos(x)*log10(d)*x) ==+> ["b"; "x"; "log(d)"; "cos(x)"] @@ -402,7 +403,7 @@ let tests = // TODO: expected: 0 Trigonometric.simplify (sin(x) + sin(y) - 2*sin(x/2+y/2)*cos(x/2-y/2)) - ==> "sin(y) - sin(x - y)/2 - sin(x/2 - y/2 - (x/2 - y/2))/2 - sin(-x/2 + y/2 - (x/2 - y/2))/2 - sin(x/2 + y/2 - (x/2 - y/2))" + ==> "-sin(-x + y)/2 - sin(x - y)/2" // "0" } test "Differentiation and Taylor Series" { @@ -482,7 +483,7 @@ let tests = solve x (2+3*x) ==> "-2/3" // sin(a)+x*cos(b)+c = 0 --> x = - solve x (sin(a)+x*cos(b)+c) ==> "-(c + sin(a))/cos(b)" + solve x (sin(a)+x*cos(b)+c) ==> "(-c - sin(a))/cos(b)" // (x^2-1)/(x+1) = 0 --> x = solve x ((x**2-1)/(x+1)) ==> "1"