Symboliq is a symbolic mathematics manipulation library written in C++ and designed to be used from within C++ (though you could certainly write a front-end client to interface with it, which I plan to do eventually).
There have been no formal releases of Symboliq yet, as it is still under significant development (I'd at least like to improve on the simplification algorithms a bit before releasing), so I haven't put together a decent web site for it yet. Furthermore, I haven't yet written any separate documentation. However, you are free to visit the project web site and either download the most current revision from CVS or browse the source code online. I particularly suggest looking at MathObject.h (which is the base object of all the derived classes and contains significant in-source documentation) and MathContainer.h (which is a kind of smart pointer class specifically for MathObjects).
You may also want to look at DoubleDispatch.h, which contains the mechanism through which multiple dispatch is implemented. If you're unfamiliar with the concept of multiple dispatch, it refers to the ability to combine the concepts of polymorphism and function overloading. Another way to put it is that it allows you to declare "virtual function arguments." This is important in Symboliq because we are frequently passing around classes derived from MathObject (but which we know nothing about) and calling functions/operators (like, for example, addition), which act in a highly class-dependent fashion: i.e., if I add two Integers together, I should do basic integer arithmetic and retrieve a new Integer, but if I add two Variable objects together, I should get a generic Addition object back. Using double dispatch I can say something like
MathContainer operator+(const MathObject &mo1, const MathObject &mo2); // calls function add(mo1,mo2)... but not directly MathContainer add(const MathObject &mo1, const MathObject &mo2) { return MathContainer(Addition(mo1, mo2)); } MathContainer add(const Integer &i1, const Integer &i2) { return MathContainer(Integer(i1.to_int() + i2.to_int())); } int main() { Integer i1(12), i2(15); Variable x("x"); MathContainer result1, result2; result1 = static_cast<const MathObject &>(i1) + static_cast<const MathObject &>(i2); // returns an Integer result2 = static_cast<const MathObject &>(i1) + static_cast<const MathObject &>(x); // returns an Addition cout << i1 << " + " << i2 << " = " << result1 << endl; cout << i1 << " + " << x << " = " << result2 << endl; } Output: 12 + 15 = 27 12 + x = 12 + x
This example isn't how Symboliq's double dispatch actually works, and I haven't shown the implementation of operator+ here (it would also require calls to members of class Integer and class Variable), but hopefully you get the point. The static casts are also of course unnecessary (Integer and Variable are both derived from MathObject), but are included to show that the compiler need not know at compile-time the types of the passed-in arguments.
This same effect could also of course be implemented through RTTI, which is actually used elsewhere in Symboliq, but for this case it quickly becomes unwieldly. See DoubleDispatch.h for more information.
If you have any questions or comments feel free to contact me at deklund@deklund.com. Thanks for your interest!
David Eklund