[Numpy-discussion] Simple multi-arg wrapper for dot()

Anne Archibald peridot.faceted@gmail....
Fri Mar 23 23:35:07 CDT 2007

```On 24/03/07, Bill Baxter <wbaxter@gmail.com> wrote:
> I mentioned in another thread Travis started on the scipy list that I
> would find it useful if there were a function like dot() that could
> multiply more than just two things.
>
> Here's a sample implementation called 'mdot'.
>
> mdot(a,b,c,d) ==> dot(dot(dot(a,b),c),d)
> mdot(a,(b,c),d) ==> dot(dot(a,dot(b,c),d)
> mdot(a,(b,(c,d))) ==> dot(a,dot(b,dot(c,d))
>
> ---
> def mdot(*args):
>     """Multiply all the arguments using matrix product rules.
>     The output is equivalent to multiplying the arguments one by one
>     from left to right using dot().
>     Precedence can be controlled by creating tuples of arguments,
>     for instance mdot(a,((b,c),d)) multiplies a (a*((b*c)*d)).
>     Note that this means the output of dot(a,b) and mdot(a,b) will differ if
>     a or b is a pure tuple of numbers.
>     """
>     if len(args)==1:
>         return args[0]
>     elif len(args)==2:
>         return _mdot_r(args[0],args[1])
>     else:
>         return _mdot_r(args[:-1],args[-1])
>
> def _mdot_r(a,b):
>     """Recursive helper for mdot"""
>     if type(a)==types.TupleType:
>         if len(a)>1:
>             a = mdot(*a)
>         else:
>             a = a[0]
>     if type(b)==types.TupleType:
>         if len(b)>1:
>             b = mdot(*b)
>         else:
>             b = b[0]
>     return numpy.dot(a,b)

You can do better:
In [1]: from numpy import *

In [2]: a = array([[0,-1],[1,0]])

In [3]: reduce(dot,(a,a,a,a))
Out[3]:
array([[1, 0],
[0, 1]])

In [4]: def mdot(*args):
...:     return reduce(dot,args)
...:

In [5]: mdot(a,a,a,a)
Out[5]:
array([[1, 0],
[0, 1]])

Not every two-line Python function has to come pre-written
--Tim Peters

Anne
P.S. reduce isn't even a numpy thing, it's one of python's
much-neglected lispy functions.
```