[GiNaC-devel] GiNaC is not a C compiler [Was: Optimized C-style output]

Warren Weckesser wweckesser at mail.colgate.edu
Thu Mar 29 13:51:56 CEST 2007


I am very interested in this discussion.  Thanks, Stefan, for sharing
your optimize_C_code() function, and getting this discussion started.

I am working on a program that generates source code for a variety of
languages, including C, Fortran, python, and Matlab, so I hope whatever
functions that come out of this discussion will be usable with languages
other than C.

Alexei suggested a function called generate_code(...) that generated
a complete function that returns the value of the expression.  That
could be useful; presumably it would check for the symbols used in
the expression, and make all of them arguments to the function. I
suggest calling this function generate_function(...) instead of
generate_code(). Another function, called generate_assignment(...),
would only generate assignments, including possibly assignments of
temporary variables.

My program generates code using variable names that were specified
in a file.  It would be useful if the target variable name of the
generate_assignment() function could be given as an argument.
For example,

   string varname = "v";
   string tmpname = "tmp";
   string tmptype = "double";
   ex f;
   ...
   generate_assignment(cout, varname, tmpname, tmptype, f);

would generate, for example,

   double tmp3 = ...
   double tmp2 = ...
   double tmp1 = ...
   v = ...

So v is the ultimate target instead of tmp0.
(My program will have already generated a proper declaration of v
before calling generate_assignment(...), but it might be useful to
have the option of including the declaration of v as double when
generate_assignment() is called.)

Often the target variable is not a simple variable name.  A lot of the
code that I generate puts the result in a vector or a matrix. The
destination might be expressed with a macro.  For example, my program
generates code to be used with the CVODE library.  To assign a value
to a vector field component, the destination of the assignment is
something like NV_Ith_S(f_,k).  For example,

   NV_Ith_S(f_,1) = -1.0/(L*L)*b*v/m-1.0/L*g*sin(theta);

or, to generate an element in a jacobian,

   DENSE_ELEM(jac_, 1, 0) = -1.0*1.0/L*cos(theta)*g;

Currently, that statement is created in a loop with code that is roughly

   cout << "DENSE_ELEM(jac_," << i << "," << j << ") = " << f << ";\n"

With generate_assignment(), this might be

   ostringstream jac_entry;
   jac_entry << "DENSE_ELEM(jac_," << i << "," << j << ")";
   generate_assignment(cout, jac_entry.str(), "tmp", "double", f);


For Fortran (assuming "implicit none" is used), it would be necessary
for the code to first figure out the names of all the temporary
variables that will be used before actually generating code, so my
program can create the appropriate declaration of these variables.
Alexei proposed this function:

   const ex find_common_subex(const ex& e, exmap& repls);

So, for Fortran output, I would call this function, and then use repls
to generate the declarations of the temporary variables.  Then I would
call generate_assignment(...) to actually create the code that does
the assignment.  (This would also work for C/C++.)

Alexei also proposed split_large_subex(...).  How would I use this
together with find_common_subex() if I want to do both to a complicated
expression?

Best regards,

Warren




More information about the GiNaC-devel mailing list