## Introduction

Working as a software developer for math and physics applications, I have got some experience of creating engineering frameworks. The **Analytics & Physics** library is one of the engineering frameworks and it is intended to work with symbolic math expressions and units of measurement (http://sergey-l-gladkiy.narod.ru/index/analytics/0-13, http://sergey-l-gladkiy.narod.ru/index/physics/0-14). It was first created for one project of geophysics data processing which required converting units of measurement and implementing ‘engineering calculator’ for math operations with borehole 1D and 2D data. The first version of the library had been created using **C#** language. Then the framework became a separate commercial project, it was translated into **Delphi** and **Java** languages. The Delphi version has been commercialized by **TMS Software** (https://www.tmssoftware.com/site/tmsanalytics.asp).

From that time, the Delphi and C# versions have been developing together. Now the frameworks allow solving wide range of math, numerical and engineering problems: converting units of measurement, including nonlinear and decibels; evaluating complicated analytical expressions; symbolic derivative calculation; numerical solution of nonlinear equations systems; linear and nonlinear least squares approximation of multidimensional data; solving systems of ordinary differential equations systems and many other. The article describes how these math and engineering problems can be solved using Delphi and C# versions of the **Analytics & Physics** framework.

## Background

Delphi and C# versions of the **Analytics & Physics** library provide `public`

API (interface) for solving engineering problems. This interface realized with some main classes. The main class for analytical and symbolic calculations is **Translator** (Delphi classes have additional ‘**T**’ prefix to follow common notations). Working with units of measurement often requires `string`

conversion, which implemented with the `UnitConverter`

class. Here is the example code for creating instances of the classes:

**var**
translator: TTranslator;
converter: TUnitConverter;
…
translator:= TTranslator.Create;
converter:= TUnitConverter.Create;
…

Translator translator = new Translator();
UnitConverter converter = new UnitConverter();

In all the code below, we suppose that an instance of the class has been created and is accessible when required.

## Symbolic Manipulations and Expression Evaluations

One of amazing features of the frameworks is symbolic derivative calculation. This means that having some analytical math expression, including functions, variables and operations, we can get symbolic expression for its derivative. Here is the code for common symbolic derivative calculation:

var
f, df: string;
begin
f:= '√(x^3+1)-A*|x^2-1|';
try
if translator.CheckSyntax(f) then
begin
df:= translator.Derivative(f,'x');
end;
except
on ex: Exception do
begin
end;
end;
end;

string f = "√(x^3+1)-A*|x^2-1|";
try
{
if (translator.CheckSyntax(f))
{
string df = translator.Derivative(f, "x");
}
}
catch (Exception ex)
{
}

As can be seen from the examples, the task of symbolic derivative evaluation solved with equivalent code (in the sense of syntactic constructions): calling method ‘`CheckSyntax`

’ for verifying formula; calling method ‘`Derivative`

’ for the evaluation and using ‘`try`

’ block for handling exceptions. The code is rather simple and straightforward. For a given math expression, we get the following symbolic derivative: ‘**3/2/√(x^3+1)*x^2-A*sgn(x^2-1)*2*x**

’. It should be noted here, that the ‘**Derivative**’ method automatically simplifies result derivative expression to present it in simpler form.

Another main functionality of the **Analytics & Physics** framework is to evaluate complicated symbolic expressions, containing variables, operators and functions. That is, if we have math expression, for an example `f=‘`**(e^x+e^-x)/2+A*B^x**’

, we can calculate its value taking into account values of the variables. The feature of the library is that it deals with data of any type. Many libraries, that intended to evaluate math expression, bounds variables and the result of evaluation by real values. But the **Analytics & Physics** framework uses one universal algorithm for evaluating expressions, containing data of any type. The algorithm controls the types and compatibility of intermediate evaluation results and automatically finds operations for types of processing data. The evaluation realized with ‘**Calculate**

’ method of the ‘**Translator**

’ class:

**function** Calculate(**const** value: **string**): TValue;

public object Calculate(string value)

The C# version returns result of ‘`object`

’ type, so, it is suitable for evaluating formula with any data. The actual type of the result can be defined via reflection mechanisms. The Delphi version uses the ‘`TValue`

’ type from RTTI unit and this type also allows storing data of any type and recognize the actual type of the stored value.

Thus, we can evaluate formula with any return type and manipulate with the result values using similar code. Here is an example of such evaluation:

var
f: string;
v: TValue;
x: TFloat;
z: TComplex;
begin
f:= '2*x^2-7*x+4';
v:= translator.Calculate(f);
x:= v.AsType<TFloat>();
f:= '2*x^2-(7+2I)*x+4';
v:= translator.Calculate(f);
z:= v.AsType<TComplex>();
end;

string f = "2*x^2-7*x+4";
object v = translator.Calculate(f);
double x = (double) v;
f = "2*x^2-(7+2I)*x+4";
v = translator.Calculate(f);
Complex z = (Complex) v;

The example evaluates two formulae, containing real variable ‘`x`

’ and operations with it. Both formula are evaluated with one function ‘`Calculate`

’, but the return results have different types, because of literal constant ‘`7+2I`

’ in the second expression. This constant is of Complex type (Re=7, Im=2), so adding real and complex, resultant value is complex.

**Analytics & Physics** framework supports basic algebraic operations (addition, subtraction, multiplication, division, power), elementary (sin, cos, log, …) and special (Legendre, Bessel, Error, Gamma) functions with real and complex data. There are also realized linear algebra operations with real and complex vectors and matrices, statistical data analysis functions and many other. The library also provides the simplest mechanism for adding various operations for any external types without modifying code of core algorithms. This mechanism will be presented later in the article.

## Units of Measurement and Conversions

Another task, often appearing in engineering applications, is using units of measurement and converting values from one to other units. **Analytics & Physics** framework provides one universal algorithm for dealing with any units of measurement, including nonlinear units and decibels. Common algorithm for conversion problem is presented with the code below:

var
s1, s2: string;
u1, u2: TUnit;
v1, v2: TFloat;
err, e1, e2: string;
r: boolean;
begin
s1:= 'kg/m s^2';
s2:= 'N/ft^2';
v1:= 1.0;
u1:=nil;
u2:=nil;
try
try
u1:= converter.ConvertString(s1, e1);
u2:= converter.ConvertString(s2, e2);
r:= (e1='') and (e2='') and TUnit.Convertible(u1,u2);
if r then
begin
v2:= TUnit.Convert(u1, u2, v1);
end
else
begin
end;
except
on E: Exception do
begin
end;
end;
finally
FreeAndNil(u1);
FreeAndNil(u2);
end;
end;

string us1 = "kg/m s^2";
string us2 = "N/ft^2";
double v1 = 1.0;
try
{
Unit u1 = converter.ConvertString(us1);
Unit u2 = converter.ConvertString(us2);
if (Unit.Convertible(u1, u1))
{
double v2 = Unit.Convert(u1, u2, v1);
}
}
catch (Exception ex)
{
}

In the example above, we have two units of measurement ‘`u1`

’ and ‘`u2`

’ for measuring pressure (or mechanical stress) values. They are created by converting `string`

representations using ‘`ConvertString`

’ method of the ‘`Converter`

’ class. Then they checked for dimensions compatibility with the ‘`Convertible`

’ method of the ‘`Unit`

’ class and if they are compatible, we use the ‘`Convert`

’ method to get ‘`v2`

’ value. This algorithm can be used for converting any units of measurement. The frameworks support more than 100 units of measurement for about 70 physical quantities. The units can be combined using standard rules for unit multiplication, division and power (http://en.wikipedia.org/wiki/Unit_of_measurement).

## Extending Functionality of the Frameworks

As was stated above, the **Analytics & Physics** framework was designed to work with data of any type and it provides simple mechanisms for extending its capabilities: introducing new units of measurement; providing operators and functions for external, user defined types; realizing symbolic derivatives for new functions. Let us consider an example of operator overloading for some user defined type.

First, we need to create our specific type. Suppose we need vectors in 3D space. The types could be like the following:

TVector3D = packed record
public
X1, X2, X3: TFloat;
constructor Create(const x1,x2,x3: TFloat); overload;
class operator Add(const v1, v2: TVector3D): TVector3D;
class operator Subtract(const v1, v2: TVector3D): TVector3D;
class operator Negative(const v: TVector3D): TVector3D;
class operator Multiply(const v1: TVector3D; const v2: TFloat): TVector3D;
class operator Divide(const v1: TVector3D; const v2: TFloat): TVector3D;
…
end;

public struct Vector3D
{
public double X1;
public double X2;
public double X3;
public Vector3D(double x1, double x2, double x3) {...}
public static Vector3D operator +(Vector3D v1, Vector3D v2) {...}
public static Vector3D operator -(Vector3D v1, Vector3D v2) {...}
public static Vector3D operator -(Vector3D v) {...}
public static Vector3D operator *(double v1, Vector3D v2) {...}
public static Vector3D operator /(Vector3D v1, double v2) {...}
...
}

Our goal is making possible using data of ‘`Vector3D`

’ in math expression and evaluating them. For this purpose, we must ‘overload operators’ in the framework environment. This is implemented with simple and straightforward approach: for overloading an operation (operator or function), new class must be implemented. Here is the example of ‘+’ operator overloading:

type
TVector3DAdd = class sealed (TGenericAddOperator<TVector3D,TVector3D,TVector3D>)
protected
function TypedOperation(const operand1: TVector3D; const operand2: TVector3D): TVector3D; override;
public
class function IsRealized: boolean; override;
end;
…
class function TVector3DAdd.IsRealized: boolean;
begin
result:= true;
end;
function TVector3DAdd.TypedOperation(const operand1, operand2: TVector3D): TVector3D;
begin
result:= operand1 + operand2;
end;

public sealed class VectorAdd : GenericAddOperator<Vector3D, Vector3D, Vector3D>
{
protected override Vector3D TypedOperation(Vector3D operand1, Vector3D operand2)
{
return operand1+operand2;
}
}

The classes for overloading the addition operation inherited from the ‘`GenericAddOperator`

’ class. Specified generic parameters defining that the first and the second operands of the addition operation are 3D vectors and the result of the operation is also vector. The overridden ‘`TypedOperation`

’ method realizes the operation itself.

As the class for the operator realized, it will be automatically found via reflection and RTTI mechanisms and used when required. So, now we can use ‘`+`

’ operation for 3D vector data. Analogously, all other operations can be realized. Here is an example of evaluating math expressions, containing 3D vector data:

var
translator: TTranslator;
v: TVariable;
f: string;
r: TValue;
begin
v:= TObjectVariable.Create('V', TValue.From(TVector3D.Create(1,-1,2)), TypeInfo(TVector3D));
translator.Add(v);
v:= TObjectVariable.Create('D', TValue.From(TVector3D.Create(0.5, 0.3,-0.7)), TypeInfo(TVector3D));
translator.Add(v);
f:= 'V*sin(Pi/4)-D/2';
r:= translator.Calculate(f);
end;

Variable v = new ObjectVariable("V", new Vector3D(1, -1, 2), typeof(Vector3D));
translator.Add(v);
v = new ObjectVariable("D", new Vector3D(0.5, 0.3, -0.7), typeof(Vector3D));
translator.Add(v);
string f = "V*sin(Pi/4)-D/2";
object r = translator.Calculate(f);

In the example code above, we created variables ‘`V`

’ and ‘`D`

’ to store vector data and added them to the ‘`translator`

’ instance. The used type ‘`ObjectVariable`

’ can store data of any type (‘`Vector3D`

’ in the case). After the variable has been added, it can be used in math expressions. Evaluating given vector expression ‘`V*sin(Pi/4)-D/2`

’ for current variable values, we get the following result ‘`r = (0.457106781186547 -0.857106781186547 1.7642135623731)`

’. The variable values can be changed via special interface of the ‘`Translator`

’ class, so we can calculate various expressions for different variable values.

It should be noted that the **Analytics & Physics** framework supports ‘implicit operator overloading’. It means that if some type has overloaded math operators, they can be automatically used for implementing corresponding operations with data for evaluating analytical expressions. Thus, for the case of the ‘`Vector3D`

’ class, there is no need to write new classes for common algebraic operators.

## Combining Numerical Methods with Symbolic Capabilities

Many of engineering problems can be stated in analytical form as a set of math expressions and formulae. But rarely, they can be solved in analytical form too. Most often, complicated engineering problems are solved using numerical methods. **Analytics & Physics** framework includes many numerical tools for solving various math and engineering problems: numerical integration, approximation, solving nonlinear equations, solving initial value problems for ordinary differential equations and other. The feature of the framework is that all numerical tools are totally incorporated with the symbolic capabilities.

As an example, let us consider a problem of integration of univariate function on some interval. The problem can be solved with the following code:

var
f: string;
x1, x2, ivalue: TFloat;
n: integer;
sf1D: TSymbolicFunction1D;
integrator: TIntegrator1DClass;
begin
f:= 'sin(x)*e^(x^2/8)';
x1:= 0.0;
x2:= 3.0;
n:= 10;
integrator:= TGauss2NodeIntegrator;
try
sf1D:= TSymbolicFunction1D.Create('x', f);
ivalue:= integrator.Integral(sf1D.F, x1, x2, n);
finally
FreeAndNil(sf1D);
end;
end;

string f = "sin(x)*e^(x^2/8)";
double x1 = 0.0;
double x2 = 3.0;
int n = 10;
Integrator1D integrator = new Gauss2NodeIntegrator();
SymbolicFunction1D sf1D = new SymbolicFunction1D("x", f);
double ivalue = integrator.Integral(sf1D.F, x1, x2, n);

In the code above, integrand function ‘`f`

’ presented in symbolic form as math expression. Such representations has many advantages, because there is no need to create special delegate methods for the numerical integration algorithm, as it is required in almost all numerical libraries. The delegate created automatically by the math expression. The symbolic data can be easily transfer through networks, stored with standard serialization algorithms and shown to the user with the appropriate form as a formula.

## Conclusions

This article introduced engineering framework **Analytics & Physics.** There are two versions of the framework – for Delphi native applications and C# version for .NET. The framework allows converting units of measurement, including nonlinear and decibels, evaluating complicated analytical expressions, symbolic derivative calculation and numerical solution of math and engineering problems. The framework’s capabilities can be extended without modifying core algorithms. The extensions can be made by introducing new units of measurement, defining operations for external, user defined types and adding symbolic derivatives for new functions. The symbolic capabilities of the framework are totally incorporated with many numerical algorithms for solving various math and engineering problems. Demo versions of the framework with example source code applications can be found here: