/** *************************************************************************** * @file GinacPrint.hh * * Header file for a class that prints GiNaC expressions in a form that * is efficient to compile and efficient to run. The main work this * class does is identifying shared sub-expressions to generate code * that only computes them once. * * When you use GinacPrint, it generates a single symbol representing * the value of the expression and a list of declarations for the * subexpressions of the initial expression. You can then use the * symbol and the declarations to print out C/C++ code to compute * the value of the expression. Here is an example. * * @code * symbol x("X"), y("Y"), z("Z"); * ex e = pow(pow(x+y,2) / (x + y + z),3); * ex dedx = diff(e,x); * * GinacPrint gprint; * * gprint.parse(e); * gprint.parse(dedx); * * std::cout << gprint.declarations() << std::endl; * std::cout << "e = " << gprint.symbol(e) << ";" << std::endl; * std::cout << "dedx = " << gprint.symbol(dedx) << ";" << std::endl; * @endcode * * Note, you can only print the declarations once, or else your * compiler will complain that some variable (a symbol) is declared * multiple times. * * The above code might generate C/C++ code like the following. * * @code * double e1 = X; * double e2 = Y; * double e3 = e1+e2; * double e4 = 6; * double e5 = pow(e3,e4); * double e6 = Z; * double e7 = e1+e2+e6; * double e8 = -3; * double e9 = pow(e7,e8); * double e10 = e5*e9; * double e11 = -4; * double e12 = pow(e7,e11); * double e13 = e5*e12*e8; * double e14 = 5; * double e15 = pow(e3,e14); * double e16 = e15*e9*e4; * double e17 = e13+e16; * * e = e10; * dedx = e17; * @endcode * * For this example, GinacPrint isn't much better than using GiNaC's * operator<<(), but for large expressions with many repeated * subexpressions GinacPrint will generate code that is significantly * more efficient to compile and execute because all the subexpressions * will be computed only once. (Note how e5 and e7 are reused here.) * * Copyright 2010 * * National Robotics Engineering Center, Carnegie Mellon University * 10 40th Street, Pittsburgh, PA 15201 * www.rec.ri.cmu.edu * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * This notice must appear in all copies of this file and its derivatives. * * History of Significant Contributions (don't put commit logs here): * 2010-05-20 Doug Baker, cape1232@yahoo.com: Created. * *************************************************************************** */ #ifndef GINACPRINT_HH #define GINACPRINT_HH #include #include #include #include using namespace GiNaC; namespace nrec { class GinacPrint { public: GinacPrint() : m_serialNumber(1) , m_datatype("double"){}; ~GinacPrint() {} /** * This will parse the expression e and create symbols for e and * all the subexpressions in e. Identical sub-expressions will * get the same symbol. You can do this on multiple different * expressions. All the subexpressions will be remembered and * returned via declarations(). * * @param e The GiNaC expression to parse. */ void parse(ex const& e); /** * This returns a string with C/C++-style declarations for * the all the symbols created via calls to parse(). * * @return A string with C/C++-style declarations. */ std::string declarations(); /** * This returns a symbol that can be used in place of the given * expression e when printing an expression. You must have * already parsed the expression before calling this function. * If you don't, the symbol will be "". * * @param e The GiNaC expression for which you want a symbol. * * @return A string with the symbol for expression e. */ std::string symbol(ex const& e); /** * With this function the default datatype can be changed. * By default it is double; Passing an empty string resets * to default. * * @param newType the new datatype * */ void setType(const std::string &newType); /** * This functions returns the current datatype. * By default it is double; * * @return the current datatype * */ const std::string & setType() const; protected: std::string genSym(); std::string print(ex const& e); std::string printOps(ex const& e, std::string const& op); size_t m_serialNumber; // These two variables contain the same information: the // expressions and the symbols that represent them. The map // is used for quick access to the symbol given an expression. // The vector is used to access the expression/symbol pairs in // the order they were created, which is the order we need // to return them via declarations(). std::map m_symbols; std::vector > m_declarations; // this string contains the datatype, the default is double. // It is possible to use any other type or T for generating code c++-templates std::string m_datatype; }; } // namespace nrec #endif // GINACPRINT_HH