ENH: add `mdot`: fast dot with multiple arguments.

This is not ready to be merged!

`mdot` makes it easy to chain `dot`. Think of `mdot` as this:

    def mdot(*args): return reduce(np.dot, args)

However, `mdot` uses the fact that matrix multiplication is associative and
finds the optimal order of multiplications with dynamic programing before
doing the mutiplication. This can speed up the multiplication quite a bit.

The algorithm follows:
Cormen, "Introduction to Algorithms", Chapter 15.2, p. 370-378

Note: currently `mdot` only works with arrays which have `ndim == 2` to avoid
ambiguities of `dot`. Also see the discussion in #4311.

TODO:
- [x] Decide if `ndim != 2` should be ok
- [x] Add unittests
- [x] decide on name. possible names are:
  - `mdot`: think "multi dot"
  - `multidot`: as above :)
  - `multi_dot`: as above :)
  - `chain_dot`
  - `fdot`: think "fast dot" (should the parameter optimize be optional then? I don't think so.)
  - `ddot`: think "multiple d for multiple dot"
  - `cdot`: think "chain dot"
  - `odot`: think "optimal do

How about: 'compute the dot product of 3 or more arrays in a single
function call, while automatically selecting the fastest evaluation order'
On 15 Oct 2014 21:08, "Stephan Hoyer" <notifications@github.com> wrote:

> In doc/release/1.10.0-notes.rst:
>
> > @@ -6,6 +6,8 @@ This release supports Python 2.6 - 2.7 and 3.2 - 3.4.
> >
> >  Highlights
> >  ==========
> > +* Addition of `np.linag.multi_dot`: Fast dot product with an arbitrary number
>
> Maybe say something like "optimally ordered matrix product" rather than
> "fast dot product"? That would be more obvious for readers (such as myself)
> who are already vaguely aware that such an algorithm exists.
>
> —
> Reply to this email directly or view it on GitHub
> <https://github.com/numpy/numpy/pull/4977/files#r18918808>.
>