`(X ** 2).sum()` is very memory-intensive and slow. I'd do it this way:

    def sqnorm(x):
        x = x.ravel()
        return np.dot(x, x)

then redefine `norm` as `sqrt(sqnorm(x))`. This way, the memory overhead is constant instead of linear and BLAS's `ddot` can be used.