15,389,661 members
Articles / General Programming / Parser
Article
Posted 3 Apr 2022

11.1K views
18 bookmarked

A Polynomials Math Parser in VB.NET

Rate me:
4 May 2022MIT3 min read
Polynomials Math Parser and Evaluator in VB.NET
The code includes five classes in order to evaluate a string of a real, complex or polynomial math expression, perhaps reducing the expression to one real or complex number or an equivalent polynomial. The math expression may or may not include variables.

Introduction

In many situations, there may be a `string` containing a math expression, such as "1+2*5", "(3+i)(3-i)" or "(z^2*w+4z^3w-w^2-4z*w^2)/(w+4z*w)", and there is the need to do the math and calculate the result. Maybe we need to calculate the result for different variables values and the result can be another polynomial. In those cases, the polynomials' parser presented here may help.

Background

The classes here are a small part -but improved- of my all free and downloadable CAS calculator. One of the goals is that these classes do not rely on other 'external' classes as happens in the CAS calculator.

The Seven Classes

• Class '`Msg10`' just contains a few messages to handle possible errors.

• Class '`G10`' holds global members like Regex patterns.
• Class '`Rational`' gives a bit more of accuracy in the operations.

• Class '`Complex`' does the complex math.

• Class '`Polynomial`' operates polynomials.

• Class '`Roots`' finds polynomials' roots and factors.
• Class '`parsePolynomial`' is in charge of dividing the input string into tokens and call accordingly to `Roots``Polynomial` or `Msg10` classes. `Roots` depends on `Polynomial` class which, in turn, depends on `Complex` and `Complex` on `Rational`. The 'tokenizing' job is done by a Regex pattern.

Tokens

The tokens groups are:

```numbers <num>
operators <op>
logical operators <lop>
functions <fn>
functions <vfn> functions retreiving a complex or polynomial array
constants <cnt>
variables <var>
any other character <any>
besides end of tokens <end> formed by an escape character Chr(27).```

The pattern looks like:

```(?s)(?<num>((\d{1,3}((\,\d{3})+(?!\d))(\.[0-9]+)?)|[\.\d]+)([eE](\s*)[-+]?[0-9]+)?)(?-s)|
(?<op>[-+*/\^])|
(?<lop>nand|mod|and|nor|xor|not|or|%|!)(?![a-zA-Z_]+)|
(?i)(?<fn>logtwo|logten|acosh|acoth|acsch|asech|asinh|atanh|floor|round|norm|conj|
coth|csch|sech|acos|acot|acsc|asec|asin|atan|cosh|sign|sinh|sqrt|tanh|abs|cos|cot|
csc|exp|log|sec|sin|sqr|tan|ln|re|im(?-i))(?![a-zA-Z_]+)|
(?i)(?<vfn>roots|(?<fct>factorize|factors|factor)(?-i))(?![a-zA-Z_]+)|
(?<cnt>e|(?i)pi(?-i))(?![a-zA-Z_]+)|
\(|\)|
(?<vars>\w)+|(?<end>\e)+|
(?<any>[^\s←\,\.])+|(?<any>\,|\.)+```

The trailing '`(?![a-zA-Z_]+)`' in, for example, `<cnt>` allows to use variables like '`epsilon`' or '`cosA`' without interfering with constants, logical operators and functions.

Function `roots` returns an array of complex numbers containg the roots of the input polynomial. Function `factor` returns an array of the input polynomial's factors. The input can also be in the form `(numerator polynomial)/(denominator polynomial)`

Using the Code

The are two possible ways of instantiation:

VB.NET
```Dim eP As New ParsePolynomial
eP.CultureInfo = New Globalization.CultureInfo("fr-FR")
...
Dim eP As New ParsePolynomial(New Globalization.CultureInfo("es-AR"))
...
```

By default, `CultureInfo` is set to "`en-US`".

Evaluation is done by calling one of the two `Evaluate()` methods.

First method:

VB.NET
```'// argument is a string:
Dim poly As Polynomial = eP.Evaluate("(x-1)*(x+1)")
...
```

First method with variables, set in a `Dictionary`(Of `String`, `Polynomial`):

VB.NET
``` Dim eP As New ParsePolynomial
Dim polyA As New Polynomial("a", 2) '// 'a' variable, 2 exponent (a^2)
polyA += New Polynomial(-1.0) ' // a ^ 2 - 1
'// argument is a string:
Dim cplx As Complex = eP.Evaluate("x*(y-i*5)")
...
```

Once the `string` has been parsed, it is possible to call the overloaded second method:

VB.NET
``` '// change "x" value (change any variable value):
eP.vars.Item("x") = New Polynomial(3)
'// argument is the Dictionary(Of String, Polynomial):
Dim polyC As Polynomial = eP.Evaluate(eP.vars)
...
```

Variables names start with a letter or underscore (_), can contain letters, numbers or underscore and can be any length.

Of course, you may call directly to the `Polynomial` class, if you don't need the parser.

The Output

The output can be just one `Polynomial`, a `Complex()` array , or `Polynomial()` array :

VB.NET
```    Dim t1 As Int64 = Now.Ticks
Dim p As Polynomial = eP.Evaluate(TBExpression.Text)
Dim t2 As New TimeSpan(Now.Ticks - t1)
If eP.vPoly.Length Then ' Response is an array of Polynomials ?
Dim s1 As String = ""
For i As Int32 = 0 To eP.vPoly.Length - 1
If eP.vPoly(i) IsNot Nothing Then
s1 += eP.vPoly(i).ToStringPolynomial(eP.Decimals, eP.Imaginary, eP.CultureInfo) + "</br>"
Else
s1 += "-------------------</br>"
End If
Next
NavigateToString(s1) ' Show in Webbrowser1
ElseIf eP.vRoots.Length Then  ' Response is an array of Complex ?
Dim s1 As String = ""
For i As Int32 = 0 To eP.vRoots.Length - 1
s1 += eP.vRoots(i).ToStringComplex(eP.Decimals, eP.Imaginary, eP.CultureInfo) + "</br>"
Next
NavigateToString(s1) ' Show in Webbrowser1
Else  ' Response is a Polynomial
NavigateToString(p.ToStringPolynomial(eP.Decimals, eP.Imaginary, eP.CultureInfo))
End If```

When calling `eP.Evaluate("factor(numerator)/(denominator)")` the return will be in  `eP.vPoly()` and a null element will separate factors from the numerator and the denominator.

You may call `Polynomial.ToString()` or `ToStringPolynomial(Optional numDecimals As Int32 = 15, Optional sImg As String = "i", Optional cultureInfo As Globalization.CultureInfo = Nothing) As String`:

VB.NET
```...
polyC.ToStringPolynomial(4, eP.Imaginary, eP.CultureInfo)
...
```

Detail Version

The detail version will show operation steps by prepending the word 'd`etail`'.

Basic Principles

The parsing method is a recursive-descent parsing: Parsing Expressions by Recursive Descent.

Evaluation method `E` calls `T` for any addition or subtraction, but `T` calls first `F` for any multiplication or subtraction, and `F` calls first `P` for any power possible power operation. `P` calls first `v` to get next token. If there is a "`(`" token, `v` calls recursively to `T`.

```E --> T {( "+" | "-" ) T}
T --> F {( "*" | "/" ) F}
F --> P ["^" F]
P --> v | "(" E ")" | "-" T
```

Step by Step Walk-throughs

Algorithm presented here englobes `T` and `F` in a single method. Besides, method `v` operates any possible function like `cos()`, `csc()`, `mod` and so on.

While writing this article, I found some glitches. If you find any further error, please let me know.

History

• 3rd April, 2022: Initial version

Share

No Biography provided

 First Prev Next
 about UI Member 153145917-Apr-22 4:38 Member 15314591 7-Apr-22 4:38
 Re: about UI Xavier Junqué i de Fortuny7-Apr-22 5:38 Xavier Junqué i de Fortuny 7-Apr-22 5:38
 factorise instead Horia Tudosie 20216-Apr-22 9:05 Horia Tudosie 2021 6-Apr-22 9:05
 Re: factorise instead Xavier Junqué i de Fortuny6-Apr-22 23:53 Xavier Junqué i de Fortuny 6-Apr-22 23:53
 my vote of 5 didicool24-Apr-22 19:41 didicool2 4-Apr-22 19:41
 Re: my vote of 5 Xavier Junqué i de Fortuny5-Apr-22 0:24 Xavier Junqué i de Fortuny 5-Apr-22 0:24
 my vote of 5 Southmountain3-Apr-22 5:58 Southmountain 3-Apr-22 5:58
 Re: my vote of 5 Xavier Junqué i de Fortuny4-Apr-22 3:14 Xavier Junqué i de Fortuny 4-Apr-22 3:14
 Last Visit: 31-Dec-99 18:00     Last Update: 8-Aug-22 5:56 Refresh 1

General    News    Suggestion    Question    Bug    Answer    Joke    Praise    Rant    Admin

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.