Hello! On Thu, Mar 29, 2007 at 07:51:56AM -0400, Warren Weckesser wrote:
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.
It should also sort those symbols, so variables declared before they used.
I suggest calling this function generate_function(...) instead of generate_code().
That would be very misleading. There are functions in C++. There is also GiNaC::function, and related DECLARE_FUNCTION_* macros. So yet another (unrelated) thing named "function" does not sound like a good idea.
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.
This function can be useful for absolutely diffrerent things. If the exact form of some lengthy subexpressions is not important for current operation (e.g. gcd()), I would call this function to replace them with symbols. If I expect the expression to have a lot of easily recognizable subexpressions I'd call it before .evalf(), then evalf() subexpressions it detected, subs() them back into the original expression, and finally evalf() it.
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?
ex e = a2*pow(x1+...+x1024, 2) + ... + a1024*pow(x1+...+x1024, 1024); exmap repls; e = find_common_subex(e, repls); // Now e should be a2*pow(symbol1, 2) ... + a1024*pow(symbol1, 1024), // and repls contains pair symbol1 => x1+...+x1024 e = split_large_subex(e, repls, 128); // e: symbol2 + symbol3 + ... + symbol8; // repls: // symbol1 => x1+...+x1024 // symbol2 => a2*pow(symbol1,2) + ... + a130*pow(symbol1,130) // symbol3 => a131*pow(symbol1,121) + ... + a259*pow(symbol1,259) // ..... // symbol8 => a898*pow(symbol1,121) + ... + a1024*pow(symbol1,1024) So repls contains "simpler" (?) expressions now. You can further split and/or find common subexpressions by iterating over repls entries. BTW, this example illustrates that such an "optimizer" does not optimize anything. It would be better to (recursively) split that expression into e = e1 + e2 e1 => a2*symbol2 + a4*pow(symbol2, 2) + ... + a1024*pow(symbol2, 512) e2 => symbol1*(a3*symbol2 + ... + a1023*pow(symbol2, 511)) symbol2 => pow(symbol1, 2) Best regards, Alexei -- All science is either physics or stamp collecting.