SymCalc C++ Documentation
Not here for C++? You can choose another language
Here, you will see how SymCalc is structured and operates inside.
If you want to get a general grasp of SymCalc abilities first, visit the intro and examples pages.
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.