Hello, On Sun, Mar 25, 2007 at 10:30:52PM +0200, Ondrej Certik wrote:
I agree with you completely: it's much better to not provide evalm() for anything but matrix (frankly, I think all those eval* things are plain evil). But with current [sloppy] type system such kind of interface is hardly ever possible. :(
Hi, this is the reason why GiNaC is using ex - so that it automatically calls eval(). We had this discussion already - it's because of C++, memory handling, speed and automatic evaluation.
But in Python I recently found a very elegant solution to this (in SymPy): I also have eval() but it's called automatically right after the construtor and if it returns a different instance, then that instance is returned. Example:
e = Add(x,x)
however "e" contains Mul(2,x), because in python you can make the Add.eval() get called right after the Add constructor. Thus Add.eval() evaluates x+x to 2*x and returns Mul(2,x). So in the end Add(x,x) is in fact the same as Mul(2,x).
Anyway, Add(A,Mul(-1,A)) is going to be zero (a number). Sometimes this is just plain wrong, e.g. think about power series: (x+O(x))-(x+O(x)) should be O(x), not zero. I don't think the problem is some C++ limitation[s]. I think the problem is the sloppy, mathematically inconsistent type system of GiNaC. What is add, exactly? Is it a polynomial? A rational expression? An algebraic one? A tensor? Or what?
And in the end, you don't have to think about eval() at all. And you don't need ex (python is handling the garbage collection automatically).
Typically those general-purpose garbage collectors suck badly. Otherwise I would be using some [Free] CAS (such as Axiom or Maxima) instead of fiddling with C++ (to put it mildly, it is certainly not my favourite programming language).
But soon I would like to implement the core of SymPy in C++ for speed and I am curious, if my system is going to be faster or slower than GiNaC.
my question is this: do you know, if it is possible to implement the above procedure in C++? and how? maybe using some macros?
IFAIK this is what eval() for: some kind of "virtual constructor". The constructor can not return an object of arbitrary type, but eval() can return anything.
Because it is certainly non standard, that you construct an instance of some class Add(x,x) and it returns an instance of a completely different class Mul(2,x).
This is certainly impossible in C++. But the question is: may be "virtual constructors" are not necessary at all? Suppose there is the Polynomial<Ring> type, and Polynomial<Ring3> operator+(const Polynomial<Ring2>&, const Polynomial<Ring1>&); Polynomial<Ring3> operator*(const Polynomial<Ring2>&, const Polynomial<Ring1>&); Polynomial<Ring3> operator*(const Polynomial<Ring2>&, const Ring1&); etc. Thus the return types are known at the compile time: if x is polynomial, then x + x is polynomial too. Thus there is no need for "virtual constructors". And compiler can catch more mistakes: Polynomial<Z> A = x; // OK Polynomial<Z> B = x + 0.5; // ERROR Best regards, Alexei -- All science is either physics or stamp collecting.