mathnet-symbolics
mathnet-symbolics copied to clipboard
How to extend with a custom function in c#?
I would like to add a ccustom function that gets evaluated when calling SymbolicExpression.Evaluate();
for instance SqFt(x, y) where I would calculate square footage from the parameters
public double SqFt(double x, double y) { return x * y; }
SymbolicExpression.Parse("SqFt(23, 15)");
When using NCalc I was able to attach a delegate that would receive the function name and arguments so I could return a result.
Is there a way to do this with MathNet?
Thanks
Hi @omnilogix ,
You can try my fork:
https://github.com/ingted/symbolic.net
I supported several function customization ways. (Check the following pages)
- https://github.com/ingted/symbolic.net/blob/main/SymbolicNet6/scripts/test.20250618.fsx
Add your function into Definition.funDict
Definition.funDict.TryRemove "iif"
Definition.funDict.TryAdd ("iif", (DTProc ([
[symX;symY;symZ], (DBFun ((fun parentScopeIdOpt procEnv symbolValues exprs ->
let g = procEnv.gCtx
let s = procEnv.sCtx
let prevO = procEnv.prevOutput
let stx = procEnv.stx
let ifTop = procEnv.depth = 0
let _, X = stx.Value.TryGetValue "x"
let _, Y_ = stx.Value.TryGetValue "y"
let _, Z_ = stx.Value.TryGetValue "z"
printfn "iif => %A %A %A %A" X Y_ Z_ exprs
let procNestedExp f =
match f with
| NestedExpr l ->
//match l with
//| [FunInvocation (Symbol "expr", ll)] ->
let evaluated = evaluate2 (Evaluate.IF_PRECISE, parentScopeIdOpt, symbolValues, procEnv) (FunInvocation (Symbol "eval", [FunInvocation (Symbol "expr", l)]))
evaluated.eRst
//| _ ->
// printfn "procNestedExp l: %A" l
// f
| _ ->
f
let Y = procNestedExp Y_
let Z = procNestedExp Z_
match X with
| FB b ->
{
procEnv
with
prevOutput = Some (if b then Y else Z)
}
| NestedExpr [FunInvocation (Symbol b, [])] when b = "true" || b = "false" ->
{
procEnv
with
prevOutput = Some (if b = "true" then Y else Z)
}
| NestedExpr l ->
printfn "l: %A" l
let evaluated = evaluate2 (Evaluate.IF_PRECISE, parentScopeIdOpt, symbolValues, procEnv) (FunInvocation (Symbol "eval", [FunInvocation (Symbol "expr",l)]))
let rst =
match evaluated.eRst with
| FB b -> b
| v -> failwithf "Invalid return type, FB <bool> expected, but %A evaluated" v
{
evaluated.eEnv
with
prevOutput = Some (if rst then Y else Z)
}
| v ->
failwithf "Invalid logical expr, FB <bool> or NestedExpr <Expression list> expected, but %A provided" v
), OutFP))
], 0, None)))
- https://github.com/ingted/symbolic.net/blob/main/FalueTests/Program.fs
using define to define function with expression string.
This fork also support variable define functionality, that means it supports symbolic scripts!!
Definition.funDict.TryRemove "main"
Definition.funDict.TryAdd ("main", DTProc ([
[], (DBExp ([
Infix.parseOrThrow "let(ttc1, 789)"
//Infix.parseOrThrow "let(y, 10000000)"
Infix.parseOrThrow "print(ttc)"
Infix.parseOrThrow "print(ttc1)"
Infix.parseOrThrow "print(ttc1)"
Infix.parseOrThrow "def(ttc, 2, 3, x, y, def(t1,1,1,x,x+100000+y), print(x*2), t1(x + y/3))"
Infix.parseOrThrow "print(ttc(ttc1, 12))"
Infix.parseOrThrow "let(gg,ttc(ttc1, 12))"
Infix.parseOrThrow "print(gg)"
], OutVar [Symbol "gg"]))
], 0, None))
(SymbolicExpression.Parse "main()").Evaluate(dict ["ttc", FloatingPoint.Real 9487.0]) |> chk (NestedList [BR 100805N]) "failed 0010"
By the way, it also supports Tensor/Deedle data frame/ConcurrentPersistedDictionary, if you don't need them, you could just comment them out in fsproj.
<IfTensorSupport>true</IfTensorSupport>
<TargetFrameworks>net9.0<!--;netstandard2.1--></TargetFrameworks>