Click here to Skip to main content
Click here to Skip to main content

Parsing Mathematical Expressions with muParser

By , 3 Mar 2012
 
muParser_cs.jpg

Introduction

This article features a C# wrapper for the muParser DLL. muParser is a fast mathematical expressions parser which transforms a mathematical expression into bytecode. Since writing it, I have received some queries about using the parser with .NET. So far, no real solution existed since muParser is native C++ code. This project will close the gap between the unmanaged parser DLL and the managed .NET environment. It is not meant to give you a detailed overview on muParser itself. Please use the following pages for this:

The functionality and member functions of the C# wrapper are almost identical, with a few exceptions mentioned in this document.

Features

The aim of this code is to provide a complete wrapper of muParser. Some of the more advanced and rarely used features could not be made accessible due to their intrinsic "unmanaged" nature. The following list shows you what features are available in C#:

  • User-defined operators
    • binary operators
    • postfix operators
    • infix operators
  • User-defined functions
    • with a fixed number of up to five arguments
    • with variable number of arguments
    • with a single string argument (for database queries)
  • User-defined constants
    • numeric constants
    • string constants
  • User-defined variables
    • unlimited in number
    • assigning variables in terms of other variables is possible
  • Custom value recognition callbacks
    • support for binary and hex values
    • can be used to implement database queries
  • Parser functions/operators

Built-in Functions

The following table gives an overview of the functions supported by the default implementation. It lists the function names, the number of arguments and a brief description.

Name Argc. Explanation
sin 1 sine function
cos 1 cosine function
tan 1 tangens function
asin 1 arcus sine function
acos 1 arcus cosine function
atan 1 arcus tangens function
sinh 1 hyperbolic sine function
cosh 1 hyperbolic cosine
tanh 1 hyperbolic tangens function
asinh 1 hyperbolic arcus sine function
acosh 1 hyperbolic arcus tangens function
atanh 1 hyperbolic arcus tangens function
log2 1 logarithm to the base 2
log10 1 logarithm to the base 10
log 1 logarithm to the base 10
ln 1 logarithm to base e (2.71828...)
exp 1 e raised to the power of x
sqrt 1 square root of a value
sign 1 sign function, -1 if x<0; 1 if x>0
rint 1 round to nearest integer
abs 1 absolute value
if 3 if ... then ... else ...
min var. min of all arguments
max var. max of all arguments
sum var. sum of all arguments
avg var. mean value of all arguments

Built-in Binary Operators

The following table lists the default binary operators supported by the parser:

Operator Meaning Priority
= assignment* -1
and logical AND 1
or logical OR 1
xor logical XOR 1
<= less or equal 2
>= greater or equal 2
!= not equal 2
== equal 2
> greater than 2
< less than 2
+ addition 3
- subtraction 3
* multiplication 4
/ division 4
^ raise x to the power of y 5

*The assignment operator is special since it changes one of its arguments and can only be applied to variables.

How It Works

The wrapper defines three classes:

  • muParser.Parser

    This is the parser object. You need to create an instance of this object in order to calculate an expression. Look at the muParser homepage for more detailed description.

  • muParser.ParserException
  • muParser.ParserVariable

Parser and ParserException are similar to their C++ counterparts and will not be documented here in detail. For details, refer to the C++ documentation and the sample source code.

ParserVariable is new and encapsulates a double value used as a variable. This is necessary since for each variable muParser needs a pointer to double. Using C#, it is hard to get a pointer that remains fixed during the lifetime of a class. ParserVariable avoids this trouble by using the DLL itself to create and release a pointer to double. In short, it hides the variable pointer from the garbage collector.

Using the Code

In order to use the code, you need the muParser.dll which is part of this archive. Make sure to place a copy of the DLL into your application directory or in a directory where the system can find it. Finally, add the file muParser.cs to your project. The following code samples assume you are either in namespace muParser or have a corresponding using muParser  statement.  

Setting Up the Parser 

In order to use the parser, create an instance of it.

 Parser parser = new Parser(Parser.EBaseType.tpDOUBLE); 
By using Parser.EBaseType.tpINT or Parser.EBaseType.tpDOUBLE as a parameter to the parser constructor you can either select an instance working with integer values or the standard instance working with double values.

Defining Variables  

Create an instance of a ParserVariable and set up a corresponding parser variable. You can default initialize the variable to a user defined value using the constructor.

ParserVariable var = new ParserVariable(10);
parser.DefineVar("my_var", var);

Setting Up and Calculating an Expression

Finally, set up the expression and calculate the result.

parser.SetExpr("10*sin(my_var)");
double val = parser.Eval();

Defining Custom Functions

You can set up your own functions and operators using delegates. The parser defines the following type that must be implemented in your code in case you'd like to use custom functions:

// Functions taking double arguments
public delegate double Fun1Delegate(double val1);
public delegate double Fun2Delegate(double val1, double val2);
public delegate double Fun3Delegate(double val1, double val2, double val3);
public delegate double Fun4Delegate(double val1, double val2, double val3, 
    double val4);
public delegate double Fun5Delegate(double val1, double val2, double val3, 
    double val4, double val5);

// Functions taking an additional string parameter
public delegate double StrFun1Delegate(String name);
public delegate double StrFun2Delegate(String name, double val1);
public delegate double StrFun3Delegate(String name, double val1, double val2);

  // Functions taking unlimited number of variables
  public delegate double MultFunDelegate(
      [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=1)] double[] array,
      int size);

Registering callbacks can be done like this:

// Add additional parser functions [optional]
parser.DefineFun("fun1", new muParser.Fun1Delegate(fun1) );
parser.DefineFun("fun2", new muParser.Fun2Delegate(fun2) );
parser.DefineFun("fun3", new muParser.Fun3Delegate(fun3) );
parser.DefineFun("fun4", new muParser.Fun4Delegate(fun4) );
parser.DefineFun("fun5", new muParser.Fun5Delegate(fun5) );
parser.DefineFun("prod", new muParser.MultFunDelegate(prod) );

// add additional operators [optional]
parser.DefineOprt("%", new muParser.Fun2Delegate(fun2), 2 );
parser.DefinePostfixOprt("m", new muParser.Fun1Delegate(fun1));

The first parameter to DefineFun or DefineOprt is the identifier, the second parameter is the delegate used as callback.

Dealing with Errors

Errors are reported by throwing an exception of type ParserException. Use the member functions of this class to get the error details.

try
{
    parser = new muParser();

    // use parser
    //...
    //...
    //...
}
catch (ParserException exc)
{
    string sMsg;
    sMsg += string.Format("  Expression:  \"{0}\"\n", exc.Expression);
    sMsg += string.Format("  Message:     \"{0}\"\n", exc.Message);
    sMsg += string.Format("  Token:       \"{0}\"\n", exc.Token);
    sMsg += string.Format("  Position:      {0}\n", exc.Position);

    Console.WriteLine(sMsg);
}

License

Copyright (c) 2007 Ingo Berg

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

History

  • Rev. 1.00 - 09.04.2007
    Initial release of the muParser C# wrapper

License

This article, along with any associated source code and files, is licensed under The MIT License

About the Author

iberg
Software Developer
Germany Germany
Member
No Biography provided

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralMy vote of 5memberAbinash Bishoyi11 Jan '13 - 3:04 
Thank you!
Question64 bit updatememberMember 943881215 Nov '12 - 10:28 
Hi thank you for your library its been very useful I have modified it to allow use on 64bit platforms as well as 32bit (with inclusion of muparser_64.dll in the same folder).
If you want the updated code message me (I couldn't see your email address on this site).
QuestionExplicitely defining variablesmemberBlack Climber30 Oct '12 - 10:09 
I am having some hard time with Explicitely defining variables.
 
Once I define my EDV pointing to some real instance of class member, it takes present value of target variable and applies it always even the target variable has been changed later.
Am I doing something wrong?
 
For example
double m_AccoutnBalance = 234;
Parser.DefineVar("AccountBalance", new ParserVariable(m_AccountBalance));
Parser.SetExpr("AccountBalance");
m_AccoutnBalance = 18000;
Console.WriteLine("Value = {0}", Parser.Eval());
 
I expect it to print Value = 18000
but it always prints Value = 234
 
What Am I doing wrong?
QuestionUsing wrapper with Mono proyect in LinumemberJuan Jose Perez12 Oct '12 - 22:40 
I wonder if this wrapper works with nono in a linux based system, I think it should work just changins the dll file by a compiled so library for linux. Have anybody try it, or have faced a similar problem??
QuestionPretty sweet visual.memberbadymojoy13 Aug '12 - 23:15 
I've been playing around with the visualizing component. Try this for yourself.
 
RED: log2(asinh(x^2+y^2))/abs(cos(x/y^4))
GREEN: log(asinh(x^2+y^2))/abs(cos(x/y^4))
BLUE: log2(asinh(x^2+y^2))-abs(cos(x/y^4))
 
I made a whole page on Facebook dedicated to art created with the picture function of this muParser wrapper. Come check me out and "Like" if you like.
 
https://www.facebook.com/PrismaticBinarium[^]
AnswerRe: Pretty sweet visual.memberiberg14 Aug '12 - 8:38 
Hi thats really cool but i'm afraid you have to take my word for it, since i'don't use facebook. Thats my favorite:
 
http://tinyurl.com/cjzh95p[^]
Questionhow can I add muparser dll to my visualstudio2010?membersivadasu7 Jun '12 - 18:50 
while adding muparser dll ,I'm getting an error like the dll could not be added and make sure that dll is accessible...
Help me how to add this dll to my project.......
Treat it as urgent
Question5 out of 5!memberAamer Alduais11 May '12 - 3:15 
Thank you!
My Favorite Quote is:
"Failure is the beginning of Success"

GeneralMy vote of 5memberRusselSSC4 Mar '12 - 3:08 
ThX
QuestionCould you tell me how to fix these errors? [modified]memberMember 86841122 Mar '12 - 23:02 
DONE:
 
1. Added muParser.cs to the c# win32 console application project and added #using muParser; in project file.
 
2. Adding both muparser.dll and muparser.lib (rename muparser32.dll to muparser.dll, ...) into C# 2010 Express to project folders Debug and Release in both bin and obj .
 
3. Adding both muparser.dll and muparser.lib into project properties|Resources
 
ERRORS:
 
1. Execute Parser parser = new Parser(); gave an error: 'muParser.Parser' does not contain a constructor that takes 0 arguments.
2. Parser only lists methods from BulkFun10delegate to Str3delegate but not all methods in muParser.cs such as SetExpr or Eval (all methods after the line
 
//---------------------------------------------------------------------------
// Parser methode wrappers
//---------------------------------------------------------------------------
#region Parser methode wrappers
 
do not appear

 
Thank you for your assistance,
 
Cha Tre

modified 3 Mar '12 - 16:10.

QuestionCould you tell me where I can get the muParser.dll?memberMember 868411229 Feb '12 - 23:34 
The package did not contain muParser.dll.
 
Thank you,
 
Cha Tre
AnswerRe: Could you tell me where I can get the muParser.dll?memberiberg1 Mar '12 - 1:25 
Precompiled dll's can be found in the sample/example2 subdirectory of the archive on sourceforge.
 
Regards,
Ingo
GeneralRe: Could you tell me where I can get the muParser.dll?memberMember 86841122 Mar '12 - 22:42 
Thank,
 
Cha Tre
GeneralRe: Could you tell me where I can get the muParser.dll?membersivadasu7 Jun '12 - 18:46 
When I add this dll it is giving an error like the dll is not accessible and make sure that dll is accessible.
please help me..
GeneralMy vote of 5memberPrafulla Hunde31 Jan '12 - 8:16 
Very useful work.Great!
Thanks for your efforts.
GeneralMy vote of 4memberHumayun Kabir Mamun3 Nov '11 - 0:13 
fine
Question.NET and 2.0memberiscoh2 Nov '11 - 0:07 
Hi,
 
I'm using the Wrapper to include muParser in my .NET app. It works very well.
I need now to switch my app to 64 bits.
I wanted to use the new version (2.0) but I didn't find the matching version of the wrapper.
I unsuccessfully tried the latest wrapper version I found. I got this error :
      BadImageFormatException was unhandled: An attempt was made to load a program with an incorrect format.
 
Thx for your help.
AnswerRe: .NET and 2.0memberiberg2 Nov '11 - 10:07 
You can download the archive from here. I have updated the binary archive.
 
Regards,
Ingo
Generalgreat work!memberMember 401148828 Mar '11 - 16:41 
You did the dirty work for me,
=)
 
thank you for sharing
GeneralC# wrapper for the muParser DLL Sample solution in Visual Studio Express 2010 [modified]memberpleabo4 Nov '10 - 7:55 
I'm interested in using muParser DLL in a multi-threaded C# plugin for Paint.net.
 
The current difficulties are:
The package from this thread downloaded and installed in .../projects/ -- OK!
----------------------------------
Visual Studio Express C++ downloaded/installed and when the DLL solution is built:
 
1> muParser.vcxproj -> C:\Users\Patrick\Documents\Visual Studio 2010\Projects\muParser\ParserDLL\Debug\muParser.dll
========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========

 
DLL looks OK!!?
 
---------------------------------
Visual Studio Express C# downloaded/installed and when the sample C# solution is ran (debug mode):
 
PInvokeStackImbalance was detected
Message: A call to PInvoke function 'example_csharp!muParser.Parser::mupSetErrorHandler' has unbalanced the stack. This is likely because the managed PInvoke signature does not match the unmanaged target signature. Check that the calling convention and parameters of the PInvoke signature match the target unmanaged signature.
&
 
The thread 'vshost.LoadReference' (0x240) has exited with code 0 (0x0).
'example_csharp.vshost.exe' (Managed (v4.0.30319)): Loaded 'C:\Users\Patrick\Documents\Visual Studio 2010\Projects\muParser\example_csharp\bin\Debug\example_csharp.exe', Symbols loaded.

 
Any help in getting the example running on VS Express 2010 would be appreciated.
 
Also, help building the DLL in a MultiThread version.
 
C++ Examples 1 & 2 seem OK in my installation. Console apps to type in probs. Not using DLL.
 
Patrick (Visual Express/C# novice)

modified on Thursday, November 4, 2010 2:07 PM

GeneralRe: C# wrapper for the muParser DLL Sample solution in Visual Studio Express 2010 [modified; issue fixed]memberiberg6 Nov '10 - 7:14 
Thats strange. I presume you use the latest archive from this article. I just checked the archive with VS2008 and can't reproduce the issue. I Downloaded the archive, unzipped it, compiled example_csharp and ran it sucessfully. The error message seems pretty clear and i believe this is a kind of conflict between the dll and the C# wrapper. According to the error message your dll does not work with the wrapper. The question is: Why? My only idea is that I recently changed the dll calling convention to __stdcall. (But this was a bad idea so i reversed it)
 
Please have a look at the directory "example_csharp\bin\Debug" and check whether there is a file named muparser.dll. Check if the date of this file is the same as the date of the executable. Make sure there is no other muparser.dll in the systems search path. (I don't know why it should be there but just in case you have a 3rd party app which dropped it into the system directory...) The next thing you could check is the dll calling convention. In the latest version it should be "__cdecl". To check the calling convention have a look at the file muParserDLL.h. In lines 30 and 32 the last word should be "__cdecl". This is the setup i have here and it appears to work. Just for curiosity: I wonder what happens if you actually change this to "__stdcall" and recompile the whole project (wrapper + dll). Does it run?
 
Thats all i can say at the moment but i'm downloading VS2010 express at the moment to check this out. I hope i can give you a more specific answer soon.
 
Best Regards,
Ingo
 


[Update]

The issue is fixed in the latest version of the archive (2010/11/08). The reason was omitting the calling convention in the DllImport declarations of the dll functions. For instance:
 

DllImport("muparser.dll", CallingConvention=CallingConvention.Cdecl)]
protected static extern IntPtr mupCreate();


modified on Monday, November 8, 2010 3:34 PM

GeneralRe: C# wrapper for the muParser DLL Sample solution in Visual Studio Express 2010 [modified; issue fixed] [modified]memberpleabo10 Nov '10 - 0:28 
The DLL was up to date with the example_csharp project.

With __stdcall in the DLL build:
System.EntryPointNotFoundException was unhandled
Message=Unable to find an entry point named 'mupDefineOprt' in DLL 'muparser.dll'.


 
With the original dll, I found that I could continue C# coding and testing by turning off the exception pInvokeStackImbalance in the managed debugging assistant (MDA). Not sure what the side effects are, but it seems to run OK.
 
Patrick
 
[Update] The latest version of the archive resolved my issues. Thanks Ingo.
modified on Thursday, November 18, 2010 11:26 AM

Generalmuparser in Visual Studios 2010memberMember 743864716 Sep '10 - 10:12 
Hi,
I've used your project several times in Visual Studios 2008, but when I convert it over to VS 2010, I'm unable to run it. I get "Error 1 error LNK1104: cannot open file 'Debug\xxx.map'" I was wondering when support for Visual Studios 2010 will be rolled out?
 
Thanks for all the great work though.
QuestionHow to use the remiander function of tow value, as 5%3 = 2groupmini_stone17 Aug '10 - 15:36 
How to use the remiander function of two value, as 5%3 = 2. I can't find the function and the operator in the "muParser" project...
 
Anybody can tell me the answer..
 
Thank you!
AnswerRe: How to use the remiander function of tow value, as 5%3 = 2memberiberg17 Aug '10 - 20:53 
You have to define it yourself using the DefineOprt member which by the way is listed as an example in the article:
 
parser.DefineOprt("%", new muParser.Fun2Delegate(fun2), 2 );

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web04 | 2.6.130516.1 | Last Updated 3 Mar 2012
Article Copyright 2007 by iberg
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid