numpy/numpy — pull request #3895 by larsmans (2013-10-11 19:48:30+00:00)
Title: ENH: use dot in linalg.norm

New take on #3893. Still no BLAS `nrm2` call, but at least `dot` is called for the common case for a significant speedup.

Timings, small array:

```
>>> %timeit sqrt(add.reduce((x.conj() * x).real, axis=None))
10000 loops, best of 3: 29.6 us per loop
>>> %timeit sqrt(np.einsum('ij,ij->', x.conj(), x).real)
100000 loops, best of 3: 19 us per loop
>>> %timeit xr = x.ravel(); sqrt(dot(xr, xr.conj()).real)
100000 loops, best of 3: 11.1 us per loop
```

Slightly larger array of complex numbers:

```
>>> x = rng.randn(101, 270) + 0j
>>> %timeit sqrt(add.reduce((x.conj() * x).real, axis=None))
1000 loops, best of 3: 445 us per loop
>>> %timeit sqrt(np.einsum('ij,ij->', x.conj(), x).real)
1000 loops, best of 3: 344 us per loop
>>> %timeit xr = x.ravel(); sqrt(dot(xr, xr.conj()).real)
1000 loops, best of 3: 286 us per loop
```

Large array, non-contiguous:

```
>>> x = rng.randn(10105, 21170)[::2, ::3]
>>> %timeit sqrt(add.reduce((x.conj() * x).real, axis=None))
1 loops, best of 3: 735 ms per loop
>>> %timeit sqrt(np.einsum('ij,ij->', x.conj(), x).real)
10 loops, best of 3: 156 ms per loop
>>> %timeit xr = x.ravel(); sqrt(dot(xr, xr.conj()).real)
1 loops, best of 3: 394 ms per loop
```

The final timing shows that using `einsum` can improve performance in some cases, but it's also more complicated because it needs separate cases for 1-d and 2-d. In the common case where the array is contiguous, this seems to be the fastest solution:

```
>>> x = x.copy()
>>> %timeit sqrt(add.reduce((x.conj() * x).real, axis=None))
1 loops, best of 3: 460 ms per loop
>>> %timeit sqrt(np.einsum('ij,ij->', x.conj(), x).real)
10 loops, best of 3: 62.8 ms per loop
>>> %timeit xr = x.ravel(); sqrt(dot(xr, xr.conj()).real)
10 loops, best of 3: 57 ms per loop
```