Matthew,

Arron has provided a fantastic summary of the issues involve.  The
summary is that even if you subclass Add/Mul/Pow, sympy will end up
creating expressions that don't use your subclasses everywhere.  This
can't be fixed without changing the core, which is outside the scope
of your project.  I know I sound like a broken record, but you should
resist the temptation to define your own Add/Mul/Pow classes.

Cheers,

Brian

On Tue, Jul 12, 2011 at 10:25 PM, Aaron Meurer <asmeu...@gmail.com> wrote:
> One thing that I have noticed with regard to overriding __mul__ and
> __rmul__ (for example) is that you can never completely control what
> happens to your class because of association.  For example, suppose
> that A and B are MatrixExprs and x is some Expr object (say, a
> Symbol).  Suppose that A*B should give a ShapeError, and that x is a
> scalar, which does not matter where it is in the expression.  Then you
> have to program it so that all of the following give ShapeError:
>
> 1. x*(A*B)
> 2. (x*A)*B
> 3. (A*x)*B
> 4. A*(x*B)
> 5. (A*B)*x
> 6. A*(B*x)
>
> Let us look at these.  Obviously, 1 and 5 will work, since you have
> complete control over A.__mul__(B).  Similarly, in 4 and 6, you will
> end up with A.__mul__(Mul(x, B)), but this is not a problem, since you
> can make A.__mul__ check for the left-most noncommutative in a Mul.
>
> But what about 2 and 3?  Here, we have __mul__ being called by a Expr
> type, namely, Mul(x, A).  You want to get B.__rmul__(Mul(x, A)), since
> you have implemented shape checking logic in MatrixExpr.__(r)mul__.
> But b.__rmul__(a) is called with a*b only if a.__mul__(b) returns
> NotImplemented.  So, basically, we need Mul.__mul__(MatrixExpr) to
> return NotImplemented.  Well, let us look at the code for Mul.__mul__
> (actually Expr.__mul__):
>
> @_sympifyit('other', NotImplemented)
> @call_highest_priority('__rmul__')
> def __mul__(self, other):
>    return Mul(self, other)
>
> Well, this is not very helpful, because the logic is buried in some
> decorators.  So let us look at the code for those decorators.  I will
> not bore you by pasting the entire code here (you can see it in
> sympy/core/decorators.py), but basically, _sympifyit makes tries to
> sympify other, and makes __mul__ return NotImplemented if it fails.  I
> am not delving into this, because sympify would not fail for
> MatrixExpr (otherwise, we would actually have a problem doing any form
> of x*A*B).
>
> So call_highest_priority seems to be a better bet.  This decorator I
> will also not paste here, but it basically lets you define
> ._op_priority on your object, and if it is greater than Expr's (which
> is quite arbitrarily set to 10.0), then it will call
> other.__rmul__(self).
>
> But wait, there's more.  _op_priority can make the above cases work,
> but * is not the only way that SymPy multiplies things.  You will also
> have to deal with variations on Mul(x, A, B).  Mul completely ignores
> _op_priority.  Unfortunately, even if this may seem like a more
> esoteric way to multiply things that you can just recommend users
> avoid, it is used internally a lot, because Mul(*args) is more
> efficient than reduce(operator.mul, args).
>
> Thus, you see that it is quite impossible to make things work 100% of
> the time without modifying the core. And actually, because of the Mul
> thing that would not work at all and that is called by so many core
> functions and methods, you will not even get something like things
> working 90% of the time, but instead things will break when used a
> certain way, and you will have hard to track bugs.
>
> Aaron Meurer
>
> On Tue, Jul 12, 2011 at 3:08 PM, Matthew Rocklin <mrock...@gmail.com> wrote:
>> Subclassing Expr has some issues as well. This is what Brian was referring
>> to. Within all of our code we use Add and Mul and don't check if instead we
>> should use some subclass of Add or subclass of Mul. If I feed a matrix
>> expression into these objects then the special matrix structure is lost.
>> This happens if, for example, you call simplify on a matrix expression.
>> I think I can get around this though with a few well placed "matrixify"
>> functions. Matrixify is a function which goes through the expression tree
>> and makes appropriate fixes. I've had good success so far with a very very
>> basic Matrixify function.
>> Brian, did you have particular horror stories trying to subclass Expr? I'm
>> enthusiastic about my approach but you seemed to have a bad experience. Can
>> you suggest difficult test cases that I should think about?
>>
>>
>> On Fri, Jul 8, 2011 at 3:22 PM, Aaron Meurer <asmeu...@gmail.com> wrote:
>>>
>>> On Fri, Jul 8, 2011 at 4:00 AM, SherjilOzair <sherjiloz...@gmail.com>
>>> wrote:
>>> > There is something I'm doing as part of my project which maybe be
>>> > useful. I'm implementing a Matrix_ wrapper class which will wrap over
>>> > low-level matrices. Its being written to replace the current Matrix
>>> > class. Algorithmic code and user-level code is being separated into
>>> > different classes. Currently, we have three internal matrices, the
>>> > DenseMatrix( a modified form of the current Matrix class), DOKMatrix
>>> > and LILMatrix. These three are essentially Data internal matrices.
>>> > The MatrixSymbol can be another object that Matrix_ (later Matrix)
>>> > would use as internal.
>>> >
>>> > Of what I understand from this discussion about the Matrix Symbol, we
>>> > need to have an object that will be treated like a Matrix everywhere,
>>> > but without the internal data. Space is being made in the Matrix
>>> > module for such an object, but for it work nicely it needs to interact
>>> > nicely with Expr objects. If its a problem subclassing Expr and
>>> > friends, I'm +1 about making a separate codebase for matrix
>>> > expressions. It is, after all, a different algebra.
>>> >
>>> > I'm not very familiar with Expr, Add, etc. but I think a separate
>>> > algebra MatrixExpr, MatrixAdd, etc. could be developed by copy-pasting
>>> > some code from Expr, Add, and modifying according to need. I say 'copy-
>>> > paste' and not subclassing as the code would be need to be modified
>>> > much before it can work on matrices.
>>>
>>> As has been discussed before, this is a bad idea. Just subclass Expr.
>>>
>>> Aaron Meurer
>>>
>>> >
>>> > Presently, I'm quite busy with this new encapsulation class Matrix_
>>> > and can only think of working fulltime on MatrixSymbol after I've
>>> > merged in my work on DOKMatrix, LILMatrix and the ongoing work on
>>> > Matrix_.
>>> >
>>> > Matthew, you could set up a wiki page on 'matrix expressions' with
>>> > some example code in it. 'symbolic matrices' can mean a few number of
>>> > things, and is somewhat vague. It would be good if everyone could see
>>> > what sort of concrete things are expected from matrix expressions.
>>> > Approaches to implement Matrix Algebra, with pros and cons listed,
>>> > could be added there for discussion, suggestion and improvement.
>>> >
>>> > Regards,
>>> > Sherjil Ozair
>>> >
>>> > --
>>> > You received this message because you are subscribed to the Google
>>> > Groups "sympy" group.
>>> > To post to this group, send email to sympy@googlegroups.com.
>>> > To unsubscribe from this group, send email to
>>> > sympy+unsubscr...@googlegroups.com.
>>> > For more options, visit this group at
>>> > http://groups.google.com/group/sympy?hl=en.
>>> >
>>> >
>>>
>>> --
>>> You received this message because you are subscribed to the Google Groups
>>> "sympy" group.
>>> To post to this group, send email to sympy@googlegroups.com.
>>> To unsubscribe from this group, send email to
>>> sympy+unsubscr...@googlegroups.com.
>>> For more options, visit this group at
>>> http://groups.google.com/group/sympy?hl=en.
>>>
>>
>> --
>> You received this message because you are subscribed to the Google Groups
>> "sympy" group.
>> To post to this group, send email to sympy@googlegroups.com.
>> To unsubscribe from this group, send email to
>> sympy+unsubscr...@googlegroups.com.
>> For more options, visit this group at
>> http://groups.google.com/group/sympy?hl=en.
>>
>
> --
> You received this message because you are subscribed to the Google Groups 
> "sympy" group.
> To post to this group, send email to sympy@googlegroups.com.
> To unsubscribe from this group, send email to 
> sympy+unsubscr...@googlegroups.com.
> For more options, visit this group at 
> http://groups.google.com/group/sympy?hl=en.
>
>



-- 
Brian E. Granger
Cal Poly State University, San Luis Obispo
bgran...@calpoly.edu and elliso...@gmail.com

-- 
You received this message because you are subscribed to the Google Groups 
"sympy" group.
To post to this group, send email to sympy@googlegroups.com.
To unsubscribe from this group, send email to 
sympy+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/sympy?hl=en.

Reply via email to