I've removed some unnecessary code that doesn't do anything, and added a few more comments.

I've scrutinized the logic of AlgebraicSum.simplify() carefully and tested a bunch of cases (including a triple-nested sum), and it is flawless, as far as I can tell.

I also modified negate() in AlgebraicSum so that it could return any AlgebraicExpression, rather than just an an AlgebraicSum. For example, if you call negate on the AlgebraicSum "-x" (representation: sum([-,var(x)])), it returns the Variable "x" (representation: var(x)), which is not an AlgebraicSum anymore.