Skip to content
73 changes: 72 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,77 @@
Math.NET Symbolics
Math.NET Symbolics (With Matrix/Vector/Customized Function supported)

2022-03-12 Now there is a private repo which supports DiffSharp Tensor within Math.NET Symbolics. (very rough/early stage)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what is it?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I add small interesting functions to support Vector, Matrix, Tensor values.

The code would look like this:

open System
open MathNet.Numerics.LinearAlgebra
open MathNet.Symbolics
open Definition
open Operators
open VariableSets.Alphabet

let V = FloatingPoint.RealVector <| vector[1.0;2.0;3.0]

let M = FloatingPoint.RealMatrix <|
        matrix [[3.0; 0.0; 0.0]
                [1.0; 2.0; 0.0]
                [0.0; 1.0; 4.0]]

let symbols2 = dict[ "a", V; "m", M ]


type A = {
    trivial: bool
}


[<EntryPoint>]
let main argv =
    let a0 = SymbolicExpression(Infix.parseOrThrow("a * 2")).Evaluate(symbols2)
    printfn "%A" a0.RealVectorValue
    let a1 = SymbolicExpression(Infix.parseOrThrow("a + 1")).Evaluate(symbols2)
    printfn "%A" a1.RealVectorValue
    let a2 = SymbolicExpression(Infix.parseOrThrow("mat_by_row(a, a)")).Evaluate(symbols2)
    printfn "%A" a2.RealMatrixValue
    let a3 = SymbolicExpression(Infix.parseOrThrow("mat_by_col(a, a)")).Evaluate(symbols2)
    printfn "%A" a3.RealMatrixValue
    let a4 = SymbolicExpression(Infix.parseOrThrow("mat_multiply(m, mat_by_col(a, vec(1.0,2.0,3.0), a), a)")).Evaluate(symbols2)
    printfn "%A" a4

    cFun ("mat_by_row", []) |> ignore

    let symV = Symbol "v"
    let symW = Symbol "w"
    let syml = dict[ "x", FloatingPoint.Real 9.0; ]
    let _ = define "t0" ([symV; symW], (v + w))
    printfn "t0: %A" <| SymbolicExpression(cFun("t0", [x; x])).Evaluate(syml)
    let _ = define "t1" ([symV; symW], Infix.parseOrThrow("t0(v, w)"))
    printfn "2 * t1(x, t1(x, x)) / t1(2 * x, x) * 4: %A" <| SymbolicExpression.Parse("2 * t1(x, t1(x, x)) / t1(2 * x, x) * 4").Evaluate(syml)
    let _ = define "t2" ([symV; symW], Infix.parseOrThrow("2 * t0(v, w) / 3"))
    printfn "2 * t2(x, x) / 3 + t2(x, x * 2): %A" <| SymbolicExpression.Parse("2 * t2(x, x) / 3 + t2(x, x * 2)").Evaluate(syml)
    printfn "t1(x, 2 * t0(x,x)): %A" <| SymbolicExpression(cFun("t1", [x; 2 * cFun("t0", [x; x])])).Evaluate(syml)
    printfn "t1(x, 2 * t1(x,x)): %A" <| SymbolicExpression(cFun("t1", [x; 2 * cFun("t1", [x; x])])).Evaluate(syml)
    printfn "t0(x, t0(x, x) * 2): %A" <| SymbolicExpression(cFun("t0", [x; cFun("t0", [x; x]) * 2])).Evaluate(syml)
    printfn "t0(x, t1(x, x) * 2): %A" <| SymbolicExpression(cFun("t0", [x; cFun("t1", [x; x]) * 2])).Evaluate(syml)

    let a5 = SymbolicExpression(Infix.parseOrThrow("2 * mat_multiply(m, mat_by_col(a, vec(1.0,2.0,3.0), a), a)")).Evaluate(symbols2)
    printfn "%A" a5

    let a6 = SymbolicExpression.Parse("2 * htensor(lo(lo(lo(vec(1,2,3), vec(4,5,6)), lo(vec(7,8,9), vec(10,11,12)))))").Evaluate(symbols2)
    printfn "%A" a6

If you are interested about it, I can add you...
(Why private? Because it is just like a toy and still a lot of works to do... )

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Output:

seq [2.0; 4.0; 6.0]
seq [2.0; 3.0; 4.0]
DenseMatrix 2x3-Double
1  2  3
1  2  3

DenseMatrix 3x2-Double
1  1
2  2
3  3

RealVector (seq [18.0; 30.0; 84.0])
t0: Real 18.0
2 * t1(x, t1(x, x)) / t1(2 * x, x) * 4: Real 8.0
2 * t2(x, x) / 3 + t2(x, x * 2): Real 26.0
t1(x, 2 * t0(x,x)): Real 45.0
t1(x, 2 * t1(x,x)): Real 45.0
t0(x, t0(x, x) * 2): Real 45.0
t0(x, t1(x, x) * 2): Real 45.0
RealVector (seq [36.0; 60.0; 168.0])
twl.Length: 1
twl.Length: 2
twl.Length: 2
v.Count: 3
v.Count: 3
twl.Length: 2
v.Count: 3
v.Count: 3
WTensor
  (DSTensor
     tensor([[[[ 2.,  4.,  6.],
          [ 8., 10., 12.]],

         [[14., 16., 18.],
          [20., 22., 24.]]]]))

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Why private? Because it is just like a toy and still a lot of works to do... )

Then, it should not be mentioned in ReadMe. Feel free to create issue though.

If you are interested about it, please leave a message in issues.

==================

For supporting code like the following:

```
#r @"src\Symbolics\bin\Debug\netstandard2.0\MathNet.Symbolics.dll"
#r @"nuget:MathNet.Numerics"
#r @"nuget:FsUnit"
#r @"nuget:FParsec"
#r @"nuget:MathNet.Numerics.FSharp"
#load @"src\Symbolics.Tests\Global.fs"
open MathNet.Numerics
open MathNet.Symbolics
open Global
open Operators
open VariableSets.Alphabet
type Expr = SymbolicExpression
let symV = Symbol "v"
let symW = Symbol "w"
let symX = Symbol "x"
let symY = Symbol "y"
let symZ = Symbol "z"
open Definition
define "test" ([symV; symW], (v + w)*2)
SymbolicExpression(Infix.parseOrThrow("2^test(x, 2 * x)")).Evaluate(dict[ "x", FloatingPoint.Real 2.0; ])
```

Result:
```
val it : FloatingPoint = Real 4096.0
```

Code:
```
SymbolicExpression(cFun("test", [x + (fromInt32 10); (fromDouble 100.0)])*2).Evaluate(dict[ "x", FloatingPoint.Real 9.0; ])
```

Result:
```
val it : FloatingPoint = Real 476.0
```


```
open System
open MathNet.Numerics.LinearAlgebra
open MathNet.Symbolics
let v = FloatingPoint.RealVector <| vector[1.0;2.0;3.0]
let symbols2 = dict[ "a", v ]
[<EntryPoint>]
let main argv =
let a0 = SymbolicExpression(Infix.parseOrThrow("a * 2")).Evaluate(symbols2)
printfn "%A" a0.RealVectorValue
let a1 = SymbolicExpression(Infix.parseOrThrow("a + 1")).Evaluate(symbols2)
printfn "%A" a1.RealVectorValue
let a2 = SymbolicExpression(Infix.parseOrThrow("mat_by_row(a, a)")).Evaluate(symbols2)
printfn "%A" a2.RealMatrixValue
let a4 = SymbolicExpression(Infix.parseOrThrow("mat_multiply(m, m, a)")).Evaluate(symbols2)
printfn "%A" a4
0 // return an integer exit code
```

Math.NET Symbolics is a basic open source **computer algebra library for .NET, Silverlight and Mono** written entirely in F#.

This project does *not* aim to become a full computer algebra system. If you need such a system, have a look at Axiom or Maxima instead, or for proprietary commercial solutions Maple, Mathematica or Wolfram Alpha.
Expand Down
18 changes: 18 additions & 0 deletions debugger/Program.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Learn more about F# at http://fsharp.org

open System
open MathNet.Numerics.LinearAlgebra
open MathNet.Symbolics
let v = FloatingPoint.RealVector <| vector[1.0;2.0;3.0]

let symbols2 = dict[ "a", v ]

[<EntryPoint>]
let main argv =
let a0 = SymbolicExpression(Infix.parseOrThrow("a * 2")).Evaluate(symbols2)
printfn "%A" a0.RealVectorValue
let a1 = SymbolicExpression(Infix.parseOrThrow("a + 1")).Evaluate(symbols2)
printfn "%A" a1.RealVectorValue
let a2 = SymbolicExpression(Infix.parseOrThrow("mat_by_row(a, a)")).Evaluate(symbols2)
printfn "%A" a2.RealMatrixValue
0 // return an integer exit code
16 changes: 16 additions & 0 deletions debugger/debugger.fsproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>

<ItemGroup>
<Compile Include="Program.fs" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\src\Symbolics\Symbolics.fsproj" />
</ItemGroup>

</Project>
3 changes: 3 additions & 0 deletions src/Symbolics.Tests/Compilation/Compilation.fs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ module Compilation =
let expr9 = x + 1
(Compile.compileExpression1OrThrow expr9 symX).Invoke(1.0) --> 2.0

let expr10' = y * y + Expression.I * y + (besselk x (Expression.I * y)) / (besselk (negate x) (Expression.I * y))
(Compile.compileComplexExpression2OrThrow expr10' symX symY).Invoke(toComplex 0.5, System.Numerics.Complex.One) --> complex 2.0 1.0

let expr1' = x
(Compile.compileComplexExpression1OrThrow expr1' symX).Invoke(toComplex 3.0) --> toComplex 3.0

Expand Down
49 changes: 49 additions & 0 deletions src/Symbolics/Definition.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
namespace MathNet.Symbolics

module Definition =

type DefType =
| DTExp of (Symbol list) * Expression
| DTFunAction of (unit -> unit)
| DTFunI1toI1 of (int -> int)
| KeyWord

let funDict = new System.Collections.Concurrent.ConcurrentDictionary<string, DefType>()

let kwlist = [ "vec", true; "mat_by_row", true; "mat_by_col", true ]

let keyWord = dict kwlist

kwlist |> List.iter (fun (k, _) -> funDict.TryAdd(k, KeyWord) |> ignore)

let defineSafe fnm exp =
if keyWord.ContainsKey fnm then
failwith "used function name"
funDict.TryAdd (fnm, DTExp exp)

let define fnm exp =
if keyWord.ContainsKey fnm then
failwith "used function name"
funDict.AddOrUpdate(
fnm
, (fun nm -> DTExp exp)
, (fun nm cur_exp -> DTExp exp)
)

let defAct fnm f =
if keyWord.ContainsKey fnm then
failwith "used function name"
funDict.AddOrUpdate(
fnm
, (fun nm -> DTFunAction f)
, (fun nm cur_exp -> DTFunAction f)
)

let def1ito1i fnm f =
if keyWord.ContainsKey fnm then
failwith "used function name"
funDict.AddOrUpdate(
fnm
, (fun nm -> DTFunI1toI1 f)
, (fun nm cur_exp -> DTFunI1toI1 f)
)
108 changes: 108 additions & 0 deletions src/Symbolics/Evaluate.fs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ open System.Collections.Generic
open MathNet.Numerics
open MathNet.Numerics.LinearAlgebra
open MathNet.Symbolics
open Definition

[<NoComparison>]
type FloatingPoint =
Expand Down Expand Up @@ -84,6 +85,7 @@ module Evaluate =
| Real x, Real y -> Real (x+y)
| Real x, Complex y | Complex y, Real x -> Complex ((complex x 0.0) + y)
| Complex x, Complex y -> Complex (x+y)
| Real x, RealVector y -> RealVector (x+y)
| RealVector x, RealVector y -> RealVector (x+y)
| ComplexVector x, ComplexVector y -> ComplexVector (x+y)
| RealMatrix x, RealMatrix y -> RealMatrix (x+y)
Expand All @@ -100,6 +102,7 @@ module Evaluate =
| Real x, Real y -> Real (x*y)
| Real x, Complex y | Complex y, Real x -> Complex ((complex x 0.0) * y)
| Complex x, Complex y -> Complex (x*y)
| Real x, RealVector y -> RealVector (x*y)
| RealVector x, RealVector y -> Real (x*y)
| ComplexVector x, ComplexVector y -> Complex (x*y)
| RealMatrix x, RealMatrix y -> RealMatrix (x*y)
Expand Down Expand Up @@ -228,6 +231,8 @@ module Evaluate =
| HankelH2, [Real nu; Complex x] -> Complex (SpecialFunctions.HankelH2 (nu, x))
| _ -> failwith "not supported"



[<CompiledName("Evaluate")>]
let rec evaluate (symbols:IDictionary<string, FloatingPoint>) = function
| Number n -> Real (float n) |> fnormalize
Expand All @@ -250,3 +255,106 @@ module Evaluate =
| Power (r, p) -> fpower (evaluate symbols r) (evaluate symbols p) |> fnormalize
| Function (f, x) -> fapply f (evaluate symbols x) |> fnormalize
| FunctionN (f, xs) -> xs |> List.map (evaluate symbols) |> fapplyN f |> fnormalize
| FunInvocation (Symbol fnm, xs) ->
let cal_param_obj_val () =
xs
|> List.map (fun exp ->
match evaluate symbols exp with
| (FloatingPoint.Real v) -> box v
| _ -> null
)
|> Array.ofList
let cal_param_real_val () =
xs
|> List.map (fun exp ->
match evaluate symbols exp with
| (FloatingPoint.Real v) -> v
| _ -> Double.NaN
)
|> Array.ofList
let cal_param_vec_val () =
xs
|> List.map (fun exp ->
match evaluate symbols exp with
| (FloatingPoint.RealVector v) -> v
| _ -> failwithf "vector parameter is required for %s" fnm
)
|> Array.ofList
let cal_param_mat_vec_val () =
xs
|> List.map (fun exp ->
match evaluate symbols exp with
| (FloatingPoint.RealVector v) -> FloatingPoint.RealVector v
| (FloatingPoint.RealMatrix v) -> FloatingPoint.RealMatrix v
| _ -> failwithf "vector parameter is required for %s" fnm
)
|> Array.ofList
if keyWord.ContainsKey fnm then
let mbr () =
let param_val = cal_param_vec_val ()
let m2 = DenseMatrix.zero<float> (param_val.Length) (param_val.[0].Count)
param_val
|> Array.iteri (fun i v ->
m2.SetRow(i, v)
)
m2
match fnm with
| "vec" ->
let param_val = cal_param_real_val ()
FloatingPoint.RealVector <| vector param_val
| "mat_by_row" ->
FloatingPoint.RealMatrix (mbr ())
| "mat_by_col" ->
let m2 = mbr()
FloatingPoint.RealMatrix <| m2.Transpose()
| "mat_multiply" ->
let param_val = cal_param_mat_vec_val ()
param_val
|> Array.skip 1
|> Array.fold (fun s a ->
match s with
| FloatingPoint.RealVector vs ->
match a with
| FloatingPoint.RealVector va ->
let r = vs * va
FloatingPoint.Real r
| FloatingPoint.RealMatrix ma ->
let r = vs * ma
FloatingPoint.RealVector r
| FloatingPoint.Real ra ->
FloatingPoint.RealVector (vs * ra)
| FloatingPoint.RealMatrix ms ->
match a with
| FloatingPoint.RealVector va ->
let r = ms * va
FloatingPoint.RealVector r
| FloatingPoint.RealMatrix ma ->
let r = ms * ma
FloatingPoint.RealMatrix r
| FloatingPoint.Real ra ->
let r = ra * ms
FloatingPoint.RealMatrix r
| FloatingPoint.Real rs ->
match a with
| FloatingPoint.RealVector va ->
let r = rs * va
FloatingPoint.RealVector r
| FloatingPoint.RealMatrix ma ->
let r = rs * ma
FloatingPoint.RealMatrix r
| FloatingPoint.Real ra ->
let r = ra * rs
FloatingPoint.Real r
) param_val.[0]
else
match funDict.[fnm] with
| DTExp (param, fx) ->
let param_val = cal_param_obj_val ()
let cmpl = Compile.compileExpressionOrThrow fx param
cmpl.DynamicInvoke(param_val:obj[]) :?> float |> Real
| DTFunI1toI1 f ->
let param_val = cal_param_real_val ()
f (int param_val.[0]) |> float |> Real



18 changes: 17 additions & 1 deletion src/Symbolics/Expression.fs
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,13 @@ type Expression =
| Power of Expression * Expression
| Function of Function * Expression
| FunctionN of FunctionN * (Expression list)
//| FunctionDef of Symbol * (Symbol list) * Expression
| FunInvocation of Symbol * (Expression list)
| ComplexInfinity
| PositiveInfinity
| NegativeInfinity
| Undefined


[<RequireQualifiedAccess>]
module Values =

Expand Down Expand Up @@ -182,6 +183,20 @@ module Operators =
| Power (xr,xp), Power (yr,yp) -> if xr <> yr then compare xr yr else compare xp yp
| Function (xf, x), Function (yf, y) -> if xf <> yf then xf < yf else compare x y
| FunctionN (xf, xs), FunctionN (yf, ys) -> if xf <> yf then xf < yf else compareZip (List.rev xs) (List.rev ys)
| FunInvocation (name1, paramdef1), FunInvocation (name2, paramdef2) ->
if name1 <> name2 then name1 < name2
else
let l1 = List.length paramdef1
let l2 = List.length paramdef2
if l1 <> l2 then l1 < l2
else
(paramdef1, paramdef2)
||> List.map2 (fun p1 p2 ->
compare p1 p2
)
|> List.find (fun result -> not result)


| Number _, _ -> true
| _, Number _ -> false
| Approximation _, _ -> true
Expand Down Expand Up @@ -395,6 +410,7 @@ module Operators =
let private PiI = multiply Pi I
let private PiIHalf = divide PiI two

let cFun(fnm, paramList) = FunInvocation (Symbol fnm, paramList)
let abs : Expression -> Expression = function
| Undefined -> undefined
| oo when isInfinity oo -> infinity
Expand Down
1 change: 1 addition & 0 deletions src/Symbolics/Symbolics.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ Minor internal simplifications and streamlining</PackageReleaseNotes>
<Compile Include="Approximation.fs" />
<Compile Include="Value.fs" />
<Compile Include="Expression.fs" />
<Compile Include="Definition.fs" />
<Compile Include="Numbers.fs" />
<Compile Include="Structure.fs" />
<Compile Include="Algebraic.fs" />
Expand Down
2 changes: 1 addition & 1 deletion src/Symbolics/Typed/Linq.fs
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ module Linq =
let constant = function
| E -> Some (Expression.Constant (complex Constants.E 0.0) :> Expression)
| Pi -> Some (Expression.Constant (complex Constants.Pi 0.0) :> Expression)
| _ -> None
| I -> Some (Expression.Constant (complex 0.0 1.0) :> Expression)
let valueType = typeof<complex>
let mathType = typeof<complex>
let mathCall1 (name : string) (a : Expression) = Expression.Call(mathType.GetMethod(name, [| valueType |]), a) :> Expression
Expand Down
Loading