On Mon, Jul 11, 2011 at 05:01:07PM -0400, Daniel Wheeler wrote:
> Hi, I am trying to find the eigenvalues and eigenvectors as well as
> the inverse for a large number of small matrices. The matrix size
> (MxM) will typically range from 2x2 to 8x8 at most. 

If you really care about speed, for matrices of this size you shouldn't
call a linear algebra pack, but simply precompute the close-form
solution. Here is sympy code that I used a while ago to generate fast
code to do inverse of SPD matrices.

G
"""
Generate the code for fast_inv
"""
from itertools import chain
from sympy import Symbol, cse, Matrix
from sympy.printing.str import StrPrinter, precedence, S

# First create a special to print squares and multiplications, rather
# than pows, as cython is not able to optimize them
class MyPrinter(StrPrinter):

    def _print_Pow(self, expr):
        PREC = precedence(expr)
        if expr.exp is S.NegativeOne:
            return '1/%s'%(self.parenthesize(expr.base, PREC))
        elif expr.exp == 2:
            return '%s*%s'%(self.parenthesize(expr.base, PREC),
                            self.parenthesize(expr.base, PREC))
        else:
            return '%s**%s'%(self.parenthesize(expr.base, PREC),
                             self.parenthesize(expr.exp, PREC))

my_printer = MyPrinter()


def code(n):
    """ Generate the code for inversing a C matrix of rank n.
    """
    l = list()
    for i in range(n):
        ll = list()
        for j in range(n):
            if j < i:
                ll.append(l[j][i])
            else:
                ll.append(Symbol('a[%i, %i]' % (i, j)))
        l.append(ll)
    m = Matrix(l)
    a = m.inverse_LU()
    vars, expr = cse([poly#.radsimp() 
                      for poly in chain(*a.tolist())])

    var_str = '\n    '.join(['cdef double %s = %s' %
                            (name, my_printer.doprint(v)) for name, v in vars])
    out_str = """

@cython.boundscheck(False)
@cython.wraparound(False)
@cython.profile(False)
@cython.cdivision(True)
@cython.cdivision_warnings(False)
cdef _inv_%i(np.ndarray[np.float_t, ndim=2, mode="c"] a):
    # Intermediate variable definition
    %s
    # Final matrix
    return np.array(%s).reshape((%i, %i))
    """ % (n, var_str, my_printer.doprint(expr), n, n)
    return out_str


out_file = file('fast_inv.pyx', 'w')

out_file.write("""
'''
Code to do a fast inverse on small symmetric matrices
'''
cimport cython

from scipy import linalg
import numpy as np
cimport numpy as np
from fast_inv import inv

""")

N = 7


for n in range(2, N+1):
    out_file.write(code(n))
    out_file.flush()
    print 'Done order %i' % n

out_file.write('''
def sym_inv(a):
    """ Return the inverse of the symetric matrix 'a'.

        This code is optimized for small symmetric matrices.
    """
    cdef int n = a.shape[0]
    if n == 1:
        return 1./a
    %s
    else:
       return inv(a) 

''' % ''.join(["""
    elif n == %i:
        return _inv_%i(np.ascontiguousarray(a))""" 
            % (i, i) for i in range(2, N+1)])

)

out_file.close()

_______________________________________________
NumPy-Discussion mailing list
[email protected]
http://mail.scipy.org/mailman/listinfo/numpy-discussion

Reply via email to