diff --git a/src/Symbolics.Tests/Compilation/Compilation.fs b/src/Symbolics.Tests/Compilation/Compilation.fs index c5e7045..111b783 100644 --- a/src/Symbolics.Tests/Compilation/Compilation.fs +++ b/src/Symbolics.Tests/Compilation/Compilation.fs @@ -43,6 +43,12 @@ module Compilation = let expr9 = x + 1 (Compile.compileExpression1OrThrow expr9 symX).Invoke(1.0) --> 2.0 + + let expr10 = min2 x y + (Compile.compileExpression2OrThrow expr10 symX symY).Invoke(12.5, 5.7) --> System.Math.Min(12.5, 5.7) + + let expr11 = max2 x y + (Compile.compileExpression2OrThrow expr11 symX symY).Invoke(12.5, 5.7) --> System.Math.Max(12.5, 5.7) let expr1' = x (Compile.compileComplexExpression1OrThrow expr1' symX).Invoke(toComplex 3.0) --> toComplex 3.0 diff --git a/src/Symbolics.Tests/Visual/Infix.fs b/src/Symbolics.Tests/Visual/Infix.fs index c003875..acc69c8 100644 --- a/src/Symbolics.Tests/Visual/Infix.fs +++ b/src/Symbolics.Tests/Visual/Infix.fs @@ -32,6 +32,14 @@ module Infix = Infix.parseOrUndefined "sin x-1" ==> "Undefined" Infix.parseOrUndefined "sin -x" ==> "sin - x" Infix.parseOrUndefined "sin" ==> "sin" + + Infix.parseOrUndefined "min(x,y)" ==> "min(x,y)" + Infix.parseOrUndefined "min ( x , y )" ==> "min(x,y)" + Infix.parseOrUndefined " min ( - x, - y ) " ==> "min(-x,-y)" + + Infix.parseOrUndefined "max(x,y)" ==> "max(x,y)" + Infix.parseOrUndefined "max ( x , y )" ==> "max(x,y)" + Infix.parseOrUndefined " max ( - x, - y ) " ==> "max(-x,-y)" Infix.parseOrUndefined "atan2(x,y)" ==> "atan2(x,y)" Infix.parseOrUndefined "atan2 ( x , y )" ==> "atan2(x,y)" diff --git a/src/Symbolics/Approximation.fs b/src/Symbolics/Approximation.fs index 5fde415..4d0aa86 100644 --- a/src/Symbolics/Approximation.fs +++ b/src/Symbolics/Approximation.fs @@ -124,6 +124,14 @@ module Approximation = let atan = function | Real a -> Real (Trig.Atan a) | Complex a -> Complex (Trig.Atan a) + let min x y = + match x, y with + | Real a, Real b -> Real (Math.Min (a, b)) + | _ -> failwith "not supported" + let max x y = + match x, y with + | Real a, Real b -> Real (Math.Max (a, b)) + | _ -> failwith "not supported" let atan2 x y = match x, y with | Real a, Real b -> Real (Math.Atan2 (a, b)) @@ -257,6 +265,8 @@ module Approximation = let applyN f xs = match f, xs with + | Min, [x; y] -> min x y + | Max, [x; y] -> max x y | Atan2, [x; y] -> atan2 x y | Log, [b; x] -> log b x | BesselJ, [nu; x] -> besselj nu x diff --git a/src/Symbolics/Calculus.fs b/src/Symbolics/Calculus.fs index 0ad0c1a..6c3fedf 100644 --- a/src/Symbolics/Calculus.fs +++ b/src/Symbolics/Calculus.fs @@ -53,6 +53,8 @@ module Calculus = | Function (AiryAiPrime, x) -> (differentiate symbol x) * x * airyai(x) | Function (AiryBi, x) -> (differentiate symbol x) * airybiprime(x) | Function (AiryBiPrime, x) -> (differentiate symbol x) * x * airybi(x) + | FunctionN (Min, _) -> failwith "not supported" + | FunctionN (Max, _) -> failwith "not supported" | FunctionN (Atan2, [x; y]) -> differentiate symbol (tan (x / y)) | FunctionN (Log, [b; x]) -> differentiate symbol ((ln x) / (ln b)) | FunctionN (BesselJ, [nu; x]) -> (differentiate symbol x) * ((besselj (nu - 1Q) x) - (besselj (nu + 1Q) x)) / 2Q diff --git a/src/Symbolics/Evaluate.fs b/src/Symbolics/Evaluate.fs index b1d1050..0dedea4 100644 --- a/src/Symbolics/Evaluate.fs +++ b/src/Symbolics/Evaluate.fs @@ -202,6 +202,8 @@ module Evaluate = let fapplyN f xs = match f, xs with + | Min, [Real x; Real y] -> Real (Math.Min(x, y)) + | Max, [Real x; Real y] -> Real (Math.Max(x, y)) | Atan2, [Real x; Real y] -> Real (Math.Atan2(x, y)) | Atan2, [Complex x; Real y] -> Complex (Complex.atan (x / (complex y 0.0))) | Atan2, [Complex x; Complex y] -> Complex (Complex.atan (x / y)) diff --git a/src/Symbolics/Expression.fs b/src/Symbolics/Expression.fs index 39faed3..4249f6d 100644 --- a/src/Symbolics/Expression.fs +++ b/src/Symbolics/Expression.fs @@ -644,6 +644,8 @@ module Operators = | Number n when n.IsNegative -> Function (Atan, Number -n) |> negate // atan(-x) = -atan(x) | Product ((Number n)::ax) when n.IsNegative -> Function (Atan, multiply (Number -n) (Product ax)) |> negate | x -> Function (Atan, x) + let min2 (x:Expression) (y:Expression) : Expression = FunctionN (Min, [x;y]) + let max2 (x:Expression) (y:Expression) : Expression = FunctionN (Max, [x;y]) let arctan2 (x:Expression) (y:Expression) : Expression = FunctionN (Atan2, [x;y]) let arccsc : Expression -> Expression = function | Undefined | ComplexInfinity -> undefined @@ -858,6 +860,8 @@ module Operators = let applyN (f: FunctionN) (xs: Expression list) : Expression = match f, xs with + | Min, [x;y] -> min2 x y + | Max, [x;y] -> max2 x y | Atan2, [x;y] -> arctan2 x y | Log, [b; x] -> log b x | BesselJ, [nu; x] -> besselj nu x @@ -959,6 +963,9 @@ type Expression with static member HankelH1 (n, x) = Operators.hankelh1 n x // Hankel Function of the First Kind static member HankelH2 (n, x) = Operators.hankelh2 n x // Hankel Function of the Second Kind + + static member Min (x, y) = Operators.min2 x y + static member Max (x, y) = Operators.max2 x y static member Apply (f, x) = Operators.apply f x static member ApplyN (f, xs) = Operators.applyN f xs diff --git a/src/Symbolics/Symbols.fs b/src/Symbolics/Symbols.fs index 65d13bb..9d5b0c8 100644 --- a/src/Symbolics/Symbols.fs +++ b/src/Symbolics/Symbols.fs @@ -20,6 +20,8 @@ type Function = type FunctionN = | Log + | Min + | Max | Atan2 | BesselJ // Bessel function of the first kind | BesselY // Bessel function of the second kind diff --git a/src/Symbolics/Typed/Linq.fs b/src/Symbolics/Typed/Linq.fs index d6630f2..cec1d03 100644 --- a/src/Symbolics/Typed/Linq.fs +++ b/src/Symbolics/Typed/Linq.fs @@ -40,7 +40,7 @@ module Linq = | Product ax -> product <| List.map denominator ax | _ -> one - let private toLambda (expr : MathNet.Symbolics.Expression) (args : Symbol list) (valueType : Type) (mathType : Type) constant value add mul div pow atan2 log abs besselj bessely besseli besselk besseliratio besselkratio hankelh1 hankelh2 : LambdaExpression option = + let private toLambda (expr : MathNet.Symbolics.Expression) (args : Symbol list) (valueType : Type) (mathType : Type) constant value add mul div pow min max atan2 log abs besselj bessely besseli besselk besseliratio besselkratio hankelh1 hankelh2 : LambdaExpression option = let valueTypeArr1 = [| valueType |] let valueTypeArr2 = [| valueType; valueType |] let argName = function |Symbol(n) -> n @@ -96,6 +96,14 @@ module Linq = let f = convertFunc func let e = convertExpr par Option.map2 id f e + | FunctionN(Min, [x;y]) -> + let exprX = convertExpr x + let exprY = convertExpr y + Option.map2 min exprX exprY + | FunctionN(Max, [x;y]) -> + let exprX = convertExpr x + let exprY = convertExpr y + Option.map2 max exprX exprY | FunctionN(Atan2, [x;y]) -> let exprX = convertExpr x let exprY = convertExpr y @@ -209,6 +217,8 @@ module Linq = let mathCall1 (name : string) (a : Expression) = Expression.Call(mathType.GetMethod(name, [| valueType |]), a) :> Expression let mathCall2 (name : string) (a : Expression) (b : Expression) = Expression.Call(mathType.GetMethod(name, [| valueType; valueType |]), a, b) :> Expression let pow = mathCall2 "Pow" + let min = mathCall2 "Min" + let max = mathCall2 "Max" let atan2 = mathCall2 "Atan2" let log a b = mathCall2 "Log" b a let abs = mathCall1 "Abs" @@ -220,7 +230,7 @@ module Linq = let besselkratio = mathCall2 "BesselKRatio" let hankelh1 = mathCall2 "HankelH1" let hankelh2 = mathCall2 "HankelH2" - toLambda expr args valueType mathType constant value add mul div pow atan2 log abs besselj bessely besseli besselk besseliratio besselkratio hankelh1 hankelh2 + toLambda expr args valueType mathType constant value add mul div pow min max atan2 log abs besselj bessely besseli besselk besseliratio besselkratio hankelh1 hankelh2 [] let formatComplexLambda (expr : MathNet.Symbolics.Expression) (args : Symbol list) : LambdaExpression option = @@ -242,6 +252,8 @@ module Linq = let mul = mathCall2 "Multiply" let div = mathCall2 "Divide" let pow = mathCall2 "Pow" + let min = mathCall2 "Min" + let max = mathCall2 "Max" let atan2 a b = mathCall1 "Atan" (div a b) let log a b = let ln = mathCall1 "Log" @@ -255,4 +267,4 @@ module Linq = let besselkratio = mathCall2 "BesselKRatio" let hankelh1 = mathCall2 "HankelH1" let hankelh2 = mathCall2 "HankelH2" - toLambda expr args valueType mathType constant value add mul div pow atan2 log abs besselj bessely besseli besselk besseliratio besselkratio hankelh1 hankelh2 + toLambda expr args valueType mathType constant value add mul div pow min max atan2 log abs besselj bessely besseli besselk besseliratio besselkratio hankelh1 hankelh2 diff --git a/src/Symbolics/Typed/TypedExpression.fs b/src/Symbolics/Typed/TypedExpression.fs index 559368b..ca1226b 100644 --- a/src/Symbolics/Typed/TypedExpression.fs +++ b/src/Symbolics/Typed/TypedExpression.fs @@ -79,10 +79,26 @@ module TypedExpression = | (ValueType.Real | ValueType.Rational), ValueType.Complex -> ValueType.Complex | _ -> ValueType.Undefined TypedExpression.FunctionN (t, (Log, [cb; cx])) + | FunctionN (Min, xs) -> + let cs = xs |> List.map convert + let t = cs |> List.map enrichedType |> List.fold mergeType ValueType.Real + TypedExpression.FunctionN (t, (Min, cs)) + | FunctionN (Max, xs) -> + let cs = xs |> List.map convert + let t = cs |> List.map enrichedType |> List.fold mergeType ValueType.Real + TypedExpression.FunctionN (t, (Max, cs)) | FunctionN (Atan2, xs) -> let cs = xs |> List.map convert let t = cs |> List.map enrichedType |> List.fold mergeType ValueType.Real TypedExpression.FunctionN (t, (Atan2, cs)) + | FunctionN (Min, xs) -> + let cs = xs |> List.map convert + let t = cs |> List.map enrichedType |> List.fold mergeType ValueType.Real + TypedExpression.FunctionN (t, (Min, cs)) + | FunctionN (Max, xs) -> + let cs = xs |> List.map convert + let t = cs |> List.map enrichedType |> List.fold mergeType ValueType.Real + TypedExpression.FunctionN (t, (Max, cs)) | FunctionN ((BesselJ | BesselY | BesselI | BesselK | BesselIRatio | BesselKRatio | HankelH1 | HankelH2) as f, [nu; z]) -> let cnu = convert nu let cz = convert z diff --git a/src/Symbolics/Visual/LaTeX.fs b/src/Symbolics/Visual/LaTeX.fs index bbf739e..855ea2a 100644 --- a/src/Symbolics/Visual/LaTeX.fs +++ b/src/Symbolics/Visual/LaTeX.fs @@ -28,6 +28,8 @@ module private LaTeXFormatter = | x -> sprintf "\\operatorname{%s}" x let latexFunctionNName = function | "log" -> "\\log" + | "min" -> "\\operatorname{min}" + | "max" -> "\\operatorname{max}" | "atan" -> "\\operatorname{atan2}" | x -> sprintf "\\operatorname{%s}" x