SymCalc C++ Documentation

Not here for C++? You can choose another language

Here, you will see how SymCalc is structured and operates inside.

List of contents

SymCalc namespace

To organize SymCalc and prevent conflits, all further classes and functions are wrapped inside of the "symcalc" namespace

You can use it like this:

```
#include <symcalc/symcalc.hpp>
using namespace symcalc; // Integrate the namespace
```

EquationBase Class

The EquationBase class is the back-bone of SymCalc. EquationBase is the base class of all other operation classes, it outlines the class structure, and it is used as the pointer type to allow polymorphism with C++.

Member Variables

`std::string type`

Type of the operation. Used for the operation identification when using polymorphism in C++.
Functions

`EquationBase(std::string el_type)`

EquationBase Constructor
`EquationBase(const EquationBase& lvalue)`

EquationBase Copy Constructor
`virtual std::string txt() const`

Used to output the text version of an expression, e.g. 5*x
`virtual double eval(std::map<std::string, double> var_hash) const`

Evaluate the expression with var_hash SymCalc variable values, as string-double pairs
`virtual EquationBase* _derivative(std::string var) const`

Differentiates self and returns a pointer to the expression
`virtual std::vector<std::string> list_variables() const`

List all the unique variables that exist in the expression.
`virtual EquationBase* _simplify() const`

Return a simplified expression using custom logic.
`virtual EquationBase* _copy_equation_base() const`

Return a pointer to a copy of the object. This function must dynamicly cast self (an EquationBase pointer), to a pointer of child type, and return a copy of the value in the pointer.
`virtual void _delete_equation_base()`

Deletes self. This function must dynamicly cast self (an EquationBase pointer), to a pointer of child type, delete the pointer.
`~EquationBase()`

Deconstructor
Math operation classes

In this section are listed all 'operation' classes that inherit from EquationBase and override the virtual functions. These classes can have own member variables to implement different functionality, and all override the virtual functions.

Variable

Implements the variable functionality in SymCalc

EquationValue

Acts as a numberical value, e.g. 5 or -152

Constant

Acts as a mathematical constant. Behaves like EquationValue during computations, but prints out as a variable

Sum

Implements the summation operation of a list of expressions

Negate

Acts as a minus sign in mathematics, or as a expression * -1. Used to create minus operations in the Sum Class

Mult

Implements the multiplication operation on a list of expressions

Div

Implements the division operation between two expressions

Power

Implements the mathematical power operation between two elements, a base and a power, e.g. base ^ power

Log

Implements the logarithm operation

Ln

Implements the natural logarithm operation

Exp

Implements the exponential function

Abs

Implements the absolute value function

Sin

Implements the sine function

Cos

Implements the cosine function

Equation Class

The Equation class is essentially a wrapper for a EquationBase pointer, but with defined operator overloadings. With this class, the SymCalc library becomes much more readable and easier to use.

Member Variables

`protected: EquationBase* eq`

The equation pointer that is wrapped by the Equation class.
Functions

`Equation(EquationBase* equation)`

Constructor that wraps a EquationBase class pointer in an Equation class
`Equation(Variable var)`

Constructor that wraps the Variable class in an Equation class
`Equation(double value)`

Constructor that wraps an EquationValue from a double, in the Equation class
`Equation(std::string var_name)`

Constructor that creates a variable with var_name and wraps in the Equation class
`Equation(std::string const_name, double value)`

Constructor that creates a constant with const_name and value and wraps in the Equation class
`Equation(const Equation& lvalue)`

Copy constructor
`Equation(const Equation& other)`

Copy constructor
`Equation(Equation&& other)`

Move constructor
`Equation& operator=(Equation&& other)`

Move assignment
`Equation& operator=(const Equation& other)`

Copy assignment
`~Equation()`

Deconstructor
`Equation pow(Equation power) const`

Returns the current equation raised to the power specified (can be an expression)
`Equation derivative(Equation variable, size_t order = 1) const`

Differentiates the equation with respect to the specified variable and specified order
`Equation derivative(size_t order = 1) const`

Differentiates the equation to the specified order. Raises an error if the equation has more than one variable
`Equation simplify() const`

Returns a simplified equation
`double eval(std::map<std::string, double> var_hash) const`

Evaluates the equation with given variable values as a string-double map
`double eval(std::map<std::Equation, double> var_hash) const`

Evaluates the equation with given variable values as a Equation-double map
`double operator()(std::map<std::string, double> var_hash) const`

Evaluates the equation just as .eval, but with a call operator
`double operator()(std::map<Equation, double> var_hash) const`

Evaluates the equation just as .eval, but with a call operator
`std::string type() const`

Returns the operation type of the wrapped EquationBase pointer
`EquationBase* copy_eq() const`

Returns the pointer to a copy of Equation's eq
Operation functions

Operation functions create new Equation objects in a more readable way. They can be either outside defined functions, or operator overloaders. They allow for easier readability and a better looking program. Here is the full list of them:

`Equation exp(const Equation eq)`

Creates a exponential equation
`Equation log(const Equation eq, const Equation base)`

Creates a logarithm equation with the specified equation and base
`Equation ln(const Equation eq)`

Creates a natural log equation
`Equation pow(const Equation base, const Equation power)`

Creates a power equation, where the first argument is raised to the second argument.
`Equation abs(const Equation eq)`

Creates a absolute value equation
`Equation sin(const Equation eq)`

Creates a sine equation
`Equation cos(const Equation eq)`

Creates a cosine equation
`friend std::ostream& operator<<(std::ostream &stream, Equation holder)`

Writes the result of the EquationBase.txt() into an output stream
`friend bool operator<(const Equation equation1, const Equation equation2)`

Needed to put the Equation class in a std::map, always returns true
`friend Equation operator+(const Equation eq1, const Equation eq2)`

Creates a new sum equation from two equations
`friend Equation operator-(const Equation eq1, const Equation eq2)`

Subtracts one equation from the other by creating a sum with eq1 and negated eq2
`friend Equation operator*(const Equation eq1, const Equation eq2)`

Multiplies two equations by creating a Mult object
`friend Equation operator/(const Equation eq1, const Equation eq2)`

Divides two equations by creating a Div object
`friend Equation operator-(const Equation eq1)`

Negates an equation, creating a Negate class object
Helper functions

There are several functions that help with managing EquationBase class pointers and other utility operations.

`EquationBase* copy(const EquationBase* start_eq)`

This is basically an alias to the EquationBase.__copy_equation_base__ function
`std::vector<EquationBase*> copy(std::vector<const EquationBase*> start_eq)`

This is the copy function, but on all elements of the vector
`void delete_equation_base(EquationBase* eq)`

This is a copy of the Equationbase.__delete_equation_base__ function, but non-member
`bool include(std::vector<T> vec, T element)`

Checks if the element is contained in the vector
Constants

As previously mentioned, SymCalc has the ability to create constants that are a mix of EquationValue and Variable.

SymCalc has a few pre-defined constants that are located in the symcalc::Constants namespace.

Here is a list of them:

`Constants::E`

Euler's number, the base of the natural log, or the limit of (1 + 1/n)^n as n tends to infinity.
`Constants::Pi`

Pi, the trigonometrical constant, that is equal to the ratio of a circle's circumference to its diameter.
Creating a new operation class

If any idea sparks your mind, it's possible to create a new SymCalc function with new features and ideas. Let's go over how to do it on an example of re-creating the absolute value function in SymCalc.

Our CustomAbs class has to inherit from the EquationBase class and override the virtual functions in it. Let's start out by writing our class:

```
#include <symcalc/symcalc.hpp>
#include <cmath>
class CustomAbs : public EquationBase{
public:
EquationBase* insides; // The expression that's inside of our abs operation
CustomAbs(EquationBase* insides) : EquationBase("abs"), insides(insides) {} // Normal constructor
CustomAbs(const CustomAbs& lvalue) : EquationBase(lvalue){
// Use the copy function to copy the insides of the lvalue CustomAbs object
this->insides = copy(lvalue.insides);
}
// Deconstructor
~CustomAbs(){
// Delete the insides on deconstruct
delete_equation_base(insides);
}
// Dynamic cast copy function
EquationBase* _copy_equation_base() const override{
const CustomAbs* casted = dynamic_cast<const CustomAbs*>(this);
return new CustomAbs(*casted); // Create a copy and return it
}
// Dynamic cast delete function
void _delete_equation_base() override{
CustomAbs* casted = dynamic_cast<CustomAbs*>(this);
delete casted;
}
// Text represantation
std::string txt() const override{
return "|" + insides->txt() + "|";
}
// Eval function
double eval(std::map<std::string, double> var_hash) const override{
double insides_eval = insides->eval(var_hash);
if(insides_eval < 0){
return -insides_eval;
}else{
return insides_eval;
}
}
// List variables function
std::vector<std::string> list_variables() const override{
return insides->list_variables();
}
// Derivative function
// |f(x)|' = (f(x) / |f(x)|) * f'(x)
// Example:
// If f(x) = x, then
// |x|' = (x / |x|) * (x)' = (x / |x|) * 1 = x / |x|
EquationBase* _derivative(std::string var) const override{
EquationBase* insides_derivative = insides->_derivative(var); // f'(x)
EquationBase* insides_copy_1 = copy(insides); // f(x)
EquationBase* insides_copy_2 = copy(insides); // f(x)
EquationBase* abs_insides = new CustomAbs(insides_copy_2); // |f(x)|
EquationBase* div = new Div(insides_copy_1, abs_insides); // f(x) / |f(x)|
EquationBase* mult = new Mult({div, insides_derivative}); // (f(x) / |f(x)|) * f'(x)
return mult;
}
// Simplify function
EquationBase* _simplify() const override{
EquationBase* simplified_insides = insides->_simplify();
if(simplified_insides->type == "abs"){
return simplified_insides; // CustomAbsolute function twice is the same as once, ||x|| = |x|
}else if(simplified_insides->type == "pow"){
// Check for a power that can be only positive, e.g. |x^2| = x^2
const Power* casted = dynamic_cast<const Power*>(simplified_insides);
if(casted->power->type == "val"){
const EquationValue* val_casted = dynamic_cast<const EquationValue*>(casted->power);
if(fmod(val_casted->value, 2) == 0){ // Check if power is divisible by 2
return simplified_insides;
}
}
}
// Implement further checks if needed
// If no simplifications work, return the insides simplified in an abs function
return new CustomAbs(simplified_insides);
}
};
```

Next, let's write out an operation function that makes using our new class simpler:

```
// Create a custom_abs() function for easier expression definition when using SymCalc
Equation custom_abs(const Equation equation){
// Create an Equation object with the pointer to a CustomAbs that holds a copy of equation's eq
return Equation(new CustomAbs(equation.copy_eq()));
}
```

Now we have our new CustomAbs class ready! Let's try using it:

```
#include <symcalc/symcalc.hpp>
// You can paste the new CustomAbs class here, or create a header and a cpp file to compile with
int main(){
Equation x ("x"); // Declare a variable
Equation fx = custom_abs(x - 4); // Use our abs function
// Print the value at x = 3, this should be |3 - 4| = |-1| = 1
std::cout << fx.eval({{x, 3}}) << std::endl; // => 1
return 0;
}
```

Other

There are some other configurations of SymCalc you could tweak to configure SymCalc how you want. Here is the list of them

SymCalc auto simplify option

The SymCalc auto simplify option is a boolean that is true by default. When the option is true, every new Equation object created will simplify itself by default. Turning off this feature will tell SymCalc not to simplify equations when created.

Here is how you can change it:

```
symcalc::SYMCALC_AUTO_SIMPLIFY = false;
// or
symcalc::SYMCALC_AUTO_SIMPLIFY = true; // the default option
```

SymCalc types configuration

If you don't want the eval function to return a double, to use a map for var hashes, or string for variable names, you can re-define them

There's one problem with it, though. Because of how a C++ library's source code is compiled before you compile the main file, you will have to define the types and then re-compile SymCalc's source code for this specific usecase.

This is how you could do it:

First, download SymCalc's source code, unzip the file and edit the include/symcalc/symcalc.hpp file to configure new like this:

```
#define SYMCALC_VALUE_TYPE float // changed from double
// Change other types if needed
```

Now, recompile the library with "make" (you could get errors when compiling examples, but they are not needed), and either run "make install", or put the headers and library files where you need them.

Well, that's the end of SymCalc's documentation! Thank you for reading it and getting involved with SymCalc!

If you have any question or ideas about SymCalc, you can contact me on my portfolio website, or by email.

SymCalc is licensed under the Apache 2.0 license. You can read more on the about page.