[Contents] [TitleIndex] [WordIndex

Symbolic computing module



Student time line

See here for the Google Summer of Code planning.

Problems to solve




At this moment the scope has a scope with named variables, and soon will have temporary variables, with a way to clean unused variables.

Types of variables

A symbolic object is a tlist with a sub-type, a reference to the internal symbolic scope. ie: a = tlist(sym","type","ref,"symbol", "a"]; b = tlist(sym","type","ref,"symbol", "b",]; a+b // is like tlist(sym", "type", "ref, "ex", "#temporal#0")

Sub-types are at this moment:


We can define an integral in GiNaC, and work with it without solve the integral, and call to an expression the eval_integ method and that it will try to solve all the integrals inside the expression.

I will define two functions, one to define an integral, and other one to solve integrals.

Note that evalf it will numerical solve an integral.

'''Symbolic Integration Tutorial''' '''Symbolic integration: the stormy decade'''


GiNaC lead us to define list with the comma operator, but in scilab there is no way to overload the comma operand, we can use the list datatype, but that will increase data access time, and it will be created a sym_list" function, that create a symbolic list, and sym_list2sci and sym_sci2list.


We can represent a matrix in two ways on GiNaC. One is a matrix class that has several functions to create matrix froms vectos, diagonal matrix, unit matrix, symbolic matrx and more, the other ways is using indexed objects and construct a two dimension object. We will use here the first one method, in that way we will define this functions:


'''On computing limits in a Symbolic Manipulation System'''


Given a system Ax=B, where A is a Matrix nxn and B a matrix nx1, the solution of this system is given by sym_solver_lineal



Legendre Polynomial

Well, there is several ways to generate the legendre Polynomial Legendre Polynomial:

Chebyshev Polynomial

There is several way to calculate this polynomial Efficient Computation of Chebyshev Polynomials in Computer Algebra

Jacobi Polynomial

Laguerre Polynomial

Associated polynomials

Several polynomials has associated polynomials, that are defined in most of cases in terms of the main polynomial, some recurrency law, or other


TODO Rosetta

This list (checklist) is constructed based on The Rosetta Stone for Computer Algebra Systems (I think that some of them don't apply to the module, but i will give them a try)



Well, GiNaC has a really nice architecture, i was reading the source code and thinking in the best way to deal with the integration capability. Basically this is how it work now:

I need to add then:

What is already done:

I think that a c++ code could be like this:

  symbols x("x"), a("a"), b("b");

  ex f = 2*x;
  cout << f.integrate(x) << endl;  // This print a symbolic indefinite integral but it doesn't computer
  cout << f.integrate(x,1,2) << endl; // This print a symbolic definite integral but it doesn't computer
  cout << f.integrate(x,a,b) << endl; // This print a symbolic definite integral but it doesn't computer

  cout << f.integrate(x).eval_integ() << endl; // This compute the symbolic indefinite integral.
  cout << f.integrate(x,1,2).eval_integ() << endl; // This compute the symbolic definite integral.
  cout << f.integrate(x,a,b).eval_integ() << endl; // This compute the symbolic definite integral.

  cout << f.integrate(x).evalf() << endl; // This should return an error.
  cout << f.integrate(x,1,2).evalf() << endl; // Compute the numerical integration.
  cout << f.integrate(x,a,b).evalf() << endl; // Compute the symbolic integration.

I decide not to change the basic or ex classes for sake of simplicity, add a new iintegral class basically copied from integral, and i will take that at a start point to the algorithm.

Right now i can define function like this on GiNaC:

static ex log_iinteg(const ex & x, unsigned iinteg_param)
        // int {log(x)} -> x * (log (x) - 1) 
        return x * (log (x) - _ex1);


REGISTER_FUNCTION(log, eval_func(log_eval).

With that now i can compute this:

#include "ginac/ginac.h"

using namespace std;
using namespace GiNaC;

int main()
    symbol x("x");
    ex f,g,h;

    f = 2*x;
    cout << f << endl;

    g = iintegral(x,f);
    cout << g << endl;

    h = g.eval_integ();
    cout << h << endl;

    f = 2*sin(x) + exp(x) + log(x);
    cout << f << endl;

    g = iintegral(x,f);
    cout << g << endl;

    h = g.eval_integ();
    cout << h << endl;

Which return:

jcardona@terminus:~/stuff/personal/symbolic/spikes/Integrals$ ./test 

Patch at: https://scilab.gitlab.io/legacy_wiki/Gsoc2009Symbolic?action=AttachFile&do=get&target=ExtendingIntegrals.patch


This has to be implemented from scratch.

Roots Of Polynomials








(I will try to write a preliminary howto of the module)


The basic symbolic datatype is the symbol, it's created with the function sym_symbol("a"), its arguments is a string with the name of the symbolic data to be created:

 a  =


 b  =


If you want to define several symbol at once use symbols that receive a variable number of strings arguments and create all the symbols at once, and return all the symbols:

-->[x,y,z] = symbols("x", "y", "z")
 z  =

 y  =

 x  =


We can construct other expression in base of the symbols previously defined:

 ans  =


 ans  =



There is three way to define a number:

 ans  =


 ans  =


We can see that the second number has an machine error by the float representation of the machine, because scilab pass to the symbolic number a number that aproch to 1.2, this could be improved by the second way of number definition:

 ans  =


 ans  =


Passing a string to sym_number we can create more accurate numbers, a third way is defining a fraction:

 ans  =


 ans  =


Evaluation of a expression is made by sym_evalf:

 ans  =


And we can define an arbitrary accurate of the floar number with sym_set_digits:

 ans  =


 ans  =


 ans  =


 ans  =


 ans  =


 ans  =


 ans  =


 ans  =


 ans  =



A symbolic list is created with a sym_list_new and you can add items with sym_list_append sym_list_prepend, get and set items with sym_list_item_get and sym_list_item_set, remove the last and first element with sym_list_remove_first and sym_list_remove_last, and clear with sym_list_clear. ie:

-->[a,b,c,d,e] = symbols("a","b","c","d","e");

-->l = sym_list_new()
 l  =


 ans  =


 ans  =


 l  =


 l  =


 l  =


 l  =


-->l1 = sym_list_new()
 l1  =


 l  =


 l  =


 ans  =


 l  =


 l  =


 l  =


=== Matrices ===

-->[x,y,z] = symbols("x","y","z");
-->m = sym_matrix_symbolic("a", 2, 3)
 m  =
 ans  =
 ans  =
 ans  =

-->l = sym_list_new();l=sym_list_append(l,x);l=sym_list_append(l,y);l=sym_list_append(l,z);l=sym_list_append(l,x);
 l  =
-->m1 = sym_matrix_diag(l)
 m1  =
-->m1 = sym_matrix_new(2,2,l)
 m1  =
-->m1 = sym_matrix_new(4,1,l)
 m1  =
-->m1 = sym_matrix_new(1,4,l)
 m1  =
-->m1 = sym_matrix_new(2,2,l)
 m1  =
 ans  =
                             !--error 999 
Error: Incorrect number of parameters.
 ans  =
 ans  =

-->a = sym_matrix_symbolic("a", 2, 2)
 a  =
 ans  =
-->b = sym_matrix_symbolic("b", 2, 1)
 b  =
-->x = sym_matrix_symbolic("x", 2, 1)
 x  =
 ans  =


-->T = sym_poly_chebyshev_T(sym_number("10"),x)
 T  =
-->U = sym_poly_chebyshev_U(sym_number("10"),x)
 U  =
 ans  =
 ans  =
 ans  =
 ans  =





Derivates are calculated with sym_diff:

-->a = sym_symbol("a") ; b = sym_symbol("b");

-->sym_diff((((a*b)^2-b^a)/(a^b))*(1-a*b^(1-a*b)), a)
 ans  =


-->c = (((a*b)^2-b^a)/(a^b))*(1-a*b^(1-a*b));

 ans  =



There are two basic functions (more comming) to handle integrals. The first is to define a integral:

-->x = symbols("x");

-->y = sin(x);

                      !--error 999
Error: Not a tlist at 3 argument

 ans  =


And the way to solve an integral is usign sym_eval_integral:

-->g = sym_integral(y,x,sym_number(0),sym_number(1))
 g  =


 ans  =


-->y = x + x^2 +x ^3;

-->g = sym_integral(y,x,sym_number(0),sym_number(1))
 g  =


 ans  =


sadly, ginac only solve polynomials integrals yet!, i will add some methods to the library using some paper that i'm collecting from ACM Digital Library.

Command List


I will try to put here some benchmark that i made in order to increase the performance of some operation, all the benchmark were tested on my Laptop (Dell 1420 with Intel Core2Duo T7300 2.00Ghz 4MBCache 2GBRam):

Define a symbol

This test measure the time that takes to create a new symbol given that there is already n symbols defined, is a constant time (the resolution of tic-toc is not enough):


Define n symbols

This test measure the time that takes to create n new symbols given that the scope is clean:


Clean scope

This test measure the time that takes to clean all the scope when it has n symbols defined:


Matrix symbolic creation

Basically the creation of a symbolic square matrix should has a complexity of O(n^2).


Concatenation of lists

This test measure the time that takes to concatenate two lists of size n:



This test measure the time that takes to calculate a factorial(n):


Chebyshev polynomial

This test measure the time that takes to calculate the expansion of sym_poly_chebyshev_T(n,x):


Legendre polynomial

This test measure the time that takes to calculate the expansion of sym_poly_legendre(n,x):


Jacobi polynomial

This test measure the time that takes to calculate the expansion of sym_poly_jacobi(n,a,b,x) with a and b defined as symbols:


This test measure the time that takes to calculate the expansion of sym_poly_jacobi(n,a,b,x) with a=1 and b defined as symbol:


This test measure the time that takes to calculate the expansion of sym_poly_jacobi(n,a,b,x) with b=1 and a defined as symbol:


This test measure the time that takes to calculate the expansion of sym_poly_jacobi(n,a,b,x) with b=1 and a=1:



Chebyshev Polynomial First Kind

The built-in function on Mathematica give us this:


After increase the performance on scilab creating a new function that return the representation of a expression without store it at the tlist we get this:


Unit test

Original Proposal

Title: Symbolic computing module Student: Jorge Eduardo Cardona Abstract: This project consists in a module that will let work with symbolic math on Scilab. There is a module that connect Scilab with Maxima through an intermediary program but this way is very slow, a faster way is to create a dynamic library of Maxima with ECL, but a native tool is a better choice. A lighter way is using GiNac library, the integration with Scilab will be easier, and there is more programmers on C++ than Lisp, so more people would enhance the tool. This approach is the one I prefer. Content:

Detailed description

There is a module created by Jean-Francois Magni that consist on a intermediary code, that create a connection between scilab and Maxima, through TCP/IP sockets. A better way to connect SciLab with Maxima could be creating a dynamic library (.lib or .dll) with ECL, and then linking this library on the module code.

Axiom is other CAS writed also on Lisp, could be used in the same way that Maxima.

GiNac is a C++ Library that work with symbolic math, maybe this could be the best approach to have a native tool, and have a better performance on it, this tool it has been developed through 10 years, and would be the more easily to maintain in the future.

With GiNac there is a better chance that the code could be maintained by several coders, and the integration just require to define a datatype on scilab, could be a mlist(['sym','name','value'],'symbol',s); and then create wrappers for the operations and the function defined on GiNaC, like expand, derivate, lsolve, evalf, determinant, and more.

GiNaC is Not a Cas, is a library, so, wee have to build a CAS system based on the library, a initial approach is creating basics datatypes that match those of GiNaC, or even more like a sym_real, sym_integer (GiNaC, has only a general Symbol, so we could create on top of it a SymbolReal, SymbolInteger, SymbolRational, SymbolIrrational), but we use the GiNaC differentiation, integration, and more.

As it say on the GiNaC tutorial, it has some disadvantages with other tools like Maxima, this is time of development, in 30 years of development of others tool the debug and enhance process is deeper than the 10 years of GiNaC, but the time that has GSoC, it's just proper to a ligther solution, and in other hand we can see this as something good, at the end the CAS system it will be in absolute control of Scilab, so, it could enhance or add feautures in pro of scilabs's goals.

We have then several approach that will be studied:

Action Plan

  1. Decide which way will be used, based on what i have searched the best way is with GiNaC, and i will assume this for the next plan.
  2. Define the features that a will be enable on scilab, like which datatypes, function and operators, and look which match with GiNaC directly. If we want something like a Symbolic_Integer or Symbolic_Irrational, that doesn't exists on GiNaC, but exists a General Symbol, we create then a new class that inheritance from Symbol with this capabilities and overload the necessary operators on c++.
  3. Define unit tests.
  4. Create like a dictionary (could be a simple std::map<std::string, ginac::symbol>) to storage the symbolic variables, this could be avoided if we add a new data type to scilab, at the code, and used the way in which scilab use this variables. At this moment i'm using a tlist to create 'sym' objects, and then overload operators, but if i pass this variables to some module functions, the code has to recreate the GiNaC variable and that add extra time, we should be able to store the variables on some data structure, and when a function is called ask for that variable.

  5. With the mechanism to save and recover the symbolic variables , either with a buffer, o recreating at every function call, we build the basic wrappers from the c code at sci_gateway to the cpp code with GiNaC basic functions.
  6. Add features that doesn't exists directly on GiNaC.

Preliminary work

I'm already work on this, and following the topic at https://scilab.gitlab.io/legacy_wiki/Scilab_Module_Architecture I build a initial 'sym' module in which i'm learning to handle with the passing of arguments and jumping to a c++ code. Looking the way that Scilab stored variables, i think the best way to stored the symbolic data, that belong to GiNaC could be a static map living on that c++ code, with some basic functions like sym_register, sym_ask. In this way when you want to find the derivative you write:

x=sym_register("x"); //the x returned is a tlist, with 'sym' as type y=sym_register("y"); sym_check("x"); y=sym_diff(x+y^2-2*x,x); // As it return a tlist, this will print a not very pretty representation. sym_print(y); // this should print a 1.

With the sym_register("x") we call a function that return a tlist, and insert a pair<string, symbol> at the static map, so it will be ready for a future use.

The x+y^2-2*x create a new tlist, that act as a tree with some overloading like this (it could be implemented at the c++ code, and ):

function x = sym(s)


function x = sym_print(s)


// Basic arithmetic operations
deff("x=%sym_a_sym(a,b)",'x = tlist([sym,name,value],+,list(a,b));');
deff("x=%sym_m_sym(a,b)",'x = tlist([sym,name,value],*,list(a,b));');
deff("x=%sym_s_sym(a,b)",'x = tlist([sym,name,value],-,list(a,b));');
deff("x=%sym_r_sym(a,b)",'x = tlist([sym,name,value],/,list(a,b));');
deff("x=%sym_p_sym(a,b)",'x = tlist([sym,name,value],^,list(a,b));'); 

// Operations with constant
deff("x=%s_a_sym(a,b)",'x = tlist([sym,name,value],constant,a) + b;');
deff("x=%s_m_sym(a,b)",'x = tlist([sym,name,value],constant,a) * b;');
deff("x=%s_s_sym(a,b)",'x = tlist([sym,name,value],constant,a) - b;');
deff("x=%s_r_sym(a,b)",'x = tlist([sym,name,value],constant,a) / b;');
deff("x=%s_p_sym(a,b)",'x = tlist([sym,name,value],constant,a) ^ b;'); 

deff("x=%sym_a_s(a,b)",'x = a + tlist([sym,name,value],constant,b);');
deff("x=%sym_m_s(a,b)",'x = a * tlist([sym,name,value],constant,b);');
deff("x=%sym_s_s(a,b)",'x = a - tlist([sym,name,value],constant,b);');
deff("x=%sym_r_s(a,b)",'x = a / tlist([sym,name,value],constant,b);');
deff("x=%sym_p_s(a,b)",'x = a ^ tlist([sym,name,value],constant,b);'); 

So, we pass this "tree" in a tlist to the sym_diff.

At this time the module already has the sym_registry and sym_check functions, the first one receive a string and then call a sym_register function that create a new symbol and put it an a map<string, symbol>, and return a tlist with type sym. The second receive a string and ask to the map if it has a symbol with that name, if it does return 1 if not return 0; I can build then the symbolic scope easily with this map.

With sym_diff we call a function that take two tlist as arguments, the second one should be a simple sym (not a tree), and capture the first tlist, and start to replace while gets down at the tree and changing symbolic string with symbols at the scope map, and at the end it has an GiNaC expression.

Look at the map handler:

#include "sym_register.hxx"
static map<string, symbol> scope;
int sym_register(const char* name)
    pair<map<string,symbol>::iterator,bool> ret;
    ret = scope.insert(pair<string, symbol>(string(name),symbol(name)));
    if (ret.second)
        return 1;
        return 0;
int sym_check(const char* name)
    if (scope.find(name) == scope.end())
        return 0;
    return 1;
int sci_sym_register(char *fname,unsigned long fname_len)
    int m, n, sp;
    int numbers[] = {0,1,2,3};
    char **name = NULL;
    char *sym_name = NULL;
    char *sym_symbol_name = NULL;
    int number_of_elements;
    int actual_postion;
    GetRhsVar(1, MATRIX_OF_STRING_DATATYPE,&m,&n,&name);
    /* Register symbol at the scope */
    sym_name = strdup("sym");
    sym_symbol_name = strdup("symbol");
    actual_postion = Rhs+1;
    CreateVar(actual_postion,TYPED_LIST_DATATYPE, &numbers[3], &numbers[1], &sp );
    CreateListVarFromPtr(actual_postion, 1,MATRIX_OF_STRING_DATATYPE, &numbers[1], &numbers[1], &sym_name);
    CreateListVarFromPtr(actual_postion, 2,MATRIX_OF_STRING_DATATYPE, &numbers[1], &numbers[1], &sym_symbol_name);
    CreateListVarFromPtr(actual_postion, 3,MATRIX_OF_STRING_DATATYPE, &numbers[1], &numbers[1], name);
    LhsVar(1) = Rhs+1;
    // Free strings!!
    return TRUE;
int sci_sym_check(char *fname,unsigned long fname_len)
    int n, m;
    char **name = NULL;
    int actual_position;
    int one=1;
    int *ret = NULL;
    ret =  (int*) MALLOC(sizeof(int)*1);
    GetRhsVar(1, MATRIX_OF_STRING_DATATYPE,&m,&n,&name);
    ret[0] = sym_check(name[0]);
    actual_position = Rhs+1;
    CreateVarFromPtr(actual_position,MATRIX_OF_INTEGER_DATATYPE, &one, &one, &ret );
    LhsVar(1) = actual_position;
    return TRUE;

Better ideas will come with more time, but this spike show that it's no hard to implement the complete system, and the GSoC period will be right for it, even when i'm not interact directly with GiNaC, is just to storage expressions, even that could be the only scope, and share the same map, with, expressions, symbols, matrix, numerics.

Well, having all the interaction part defined and correcty implemented is just a matter of use the features of GiNaC, and also enhnace some of them.


About you

* I'm a student of electronics engineering at Universidad Pontificia Bolivariana, with experience on tools like scilab, scicos, matlab, simulink, labview, openmodelica, and several python libraries for simulation, numerical math.

* I have experience in programming with C and C++, like 5 years now.

* I study but i'm also work on a company half-time (until the next week, i need more time to do my undergraduate thesis) and I'm been involved in a couple of software development project, using XP methodology.

* In my engineer career i received great math and physics background, and personally i really enjoy all the modeling and simulation theory (I actually expend a lot of money on amazon buying books of theory of modeling and simulation of discrete systems :) )

* I knew about scilab like 4 years ago, but i'm start using it like 2 and half, and for the last year i used a lot because my undergraduate work project.

* I'm really interested on this project, i found it like a opportunity also to maybe publish a paper about the construction of a CAS and how it works for a Mathematical meeting at August at Cali.

Original Comments

I end a prototype, that store all expressions on the scope, and overload basic arithmetic operations, and create a sym_diff to do this:

 ans  =
 ans  =
 ans  =
 ans  =

I'm storing all expression at the scope, even intermediary expressions, because i can find a way to identify when someone type just a+b or c=a+b, and at the first case, the expression exists only for a while, but the other case is a more long-lived value, and even if i delete the c variable of the scilab scope, i should do the same with the expression at the symbolic scope, i was thinking on a clean_symbolic_scope function to do that. But it's a good start.

2022-09-08 09:27