First off, pragmatically speaking, is there a reason why you need to use the core Mul instead of writing your own custom Mul for the quantum stuff? I am just saying this because even though I agree that we need this change, changing anything in the core is very difficult and time consuming, because the code is so fragile, and you also have to pay close attention to speed concerns.
Also, Mul is optimized for commutative arguments, with non-commutatives special cased (read "hacked in"). I am thinking it might be smarter to have separate NCMul for general non-commutatives anyway. So basically, these suggestions are on how to fix issue 1941, because as I see it, validating whether two objects can be multiplied together is just a special case of objects that combine with each other specially. On Jul 21, 2010, at 1:34 PM, Brian Granger wrote: > Hi, > > We are running into some issues with Mul in the quantum stuff. There > are two main things: > > 1. How Mul combines adjacent args. This one may prove to be the more difficult of the two to solve, because of the way Python evaluates expressions like a*b*c. Also, you have to consider that no matter how you try to make things work with __mul__ and __rmul__, it can always be thrown off with something like a*(b*c). Option 1 alone might not work for this reason. > 2. How Mul decides if two adjacent args can be multiplied. > > For now, let's focus on the second of these. The difficulty right now > is that Mul allow any two Exprs to be multiplied. But in quantum > mechanics, certain things can't be multiplied. For example, the > following don't make sense: > > Ket('a')*Operator('O) > Operator('O')*Bra('a') > > We would like to add logic to check for these cases into the > __mul__/__rmul__ methods of Operator and State. But, this logic will > never be triggered in situations like this: > > Bra('a')*Ket('a')*Operator('O) = Mul(Bra('a'), Ket('a'))*Operator('O') > > Because the Mul*Operator triggers Mul.__mul__ (which has no validation > for Operators or States) rather than Operator.__rmul__. > > I see two ways out of this: > > 1. Handle this like numpy arrays that have an __array_priority__ > attribute. The idea is that the array having the highest numeric > value of the __array_priority__ attribute would have its __mul__ or > __rmul__ method called. This would make it possible for: > > Mul(Bra('a'), Ket('a'))*Operator('O') to trigger Operator.__rmul__ > > This solution would not required changes to Mul, only to the __mul__ > and __rmul__ methods of Expr. It would also require going through > sympy and adding the priority atttributes to relevant classes. > > 2. To add a new set of methods to Expr that are used by Mul to > validate if two things could be multiplied. This is more flexible. I > propose methods like: > > _validate_mul(self, other) > _validate_rmul(self, other) > It seems to me like you would have to have both options. The _validate_mul (or combine_mul, as Ondrej called it in http://github.com/certik/sympyx/commits/handler) would have to be there to handle the special multiplication behaviors. But I think you also need some kind of priority system to break ties of more than one object in the Mul has such a method. If you just do validation (no combining), then maybe you could do without option 1, except you will have to accept the fact that _validate_mul will always be called before _validate_rmul. By the way, it is more general to send to the combination method the whole list of objects that have been gathered together already. This is for things that combine into each other, such as infinities and Order, so they can pull everything into themselves. > The end of Mul.flatten would check for these attributes and then > validate adjacent objects to make sure they could really be > multiplied. This would help us with symbolic Matrices and Tensors for > example, because these methods could do shape compatibility tests. > > This issue is also related to how combines are done in Mul.flatten, > but I think we might be able to resolve this by itself. Thoughts? Maybe for now you could do validation separate from combination, if it's easier to handle. Ultimately, I would like to see both separated out into the objects. The validation is a trivial special case of the combination, but not the other way around, because combination requires handling all args, not just adjacent ones. On the other hand, the issue #1 you name above could cause efficiency problems for the combination, so might need to be solved concurrently. Aaron Meurer > > Cheers, > > Brian > -- You received this message because you are subscribed to the Google Groups "sympy" group. To post to this group, send email to sy...@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.