# [PYTHON MATRIX-SIG] Release 1.0alpha1 now available

11 Aug 1996 23:59:32 +0300

```Konrad Hinsen      <hinsen@physik.rwth-aachen.de> writes:

> As soon as I am back in business, I will update my LAPACK interface
> for the new version. I don't pretend that it is the last word on
> linear algebra libraries (some problems, like application to different
> types of matrices (symmetric etc.) have been completely ignored
> until now), but it has worked quite well for me in the past, and I have
> a couple of application algorithms that use it.

Well, I need your LAPACK interface right now... see below. :)

By the way, dot(a,b) of the package Numeric now seems to reduce over
the same axis for both a and b. While this seems sensible and
efficient, especially if the axis is -1, the behaviour looks strange
for a newcomer who maybe expects to find a matrix multiplication
function. Should there be a function behaving like the ordinary matrix
multiplication for 2D arrays, say dot2(), so that dot(a,b) would be
equal to dot2(a,transpose(b)) (for 2D arrays)? On the other hand, this
kind of behaviour does not mean anything sensible for N-dimensional
arrays, or does it?

# This module contains high-level Python interfaces to the
# LAPACK library.
#
# Written by Konrad Hinsen <hinsenk@ere.umontreal.ca>
# last revision: 1996-3-13
#
# Modified 1996-3-19 by Doug Heisterkamp
#        Change type of pivots from "i" to "l" in solveLinearEquations
#
# Modified 1996-8-11 by Janne Sinkkonen <janne@iki.fi>
#        Made compatible with NumPy 1.0alpha1. A bug in eigenvalues()
#        (triggered by complex arguments) corrected. dot() is now
#        _dot2() and unitMatrix() is _unitMatrix().

# import Numeric,umath
import Numeric
import copy

transpose=Numeric.transpose
zeros=Numeric.zeros
cp=copy.copy

# Error object

LinAlgError = 'LinAlgError'

# Helper routines

_lapack_type = {'f': 0, 'd': 1, 'F': 2, 'D': 3}
_lapack_letter = ['s', 'd', 'c', 'z']
_array_kind = {'i':0, 'l': 0, 'f': 0, 'd': 0, 'F': 1, 'D': 1}
_array_precision = {'i': 1, 'l': 1, 'f': 0, 'd': 1, 'F': 0, 'D': 1}
_array_type = [['f', 'd'], ['F', 'D']]

def _commonType(*arrays):
kind = 0
precision = 0
for a in arrays:
t = a.typecode()
kind = max(kind, _array_kind[t])
precision = max(precision, _array_precision[t])
return _array_type[kind][precision]

def _castCopyAndTranspose(type, *arrays):
cast_arrays = ()
for a in arrays:
if a.typecode() == type:
cast_arrays = cast_arrays + (cp(transpose(a)),)
else:
cast_arrays = cast_arrays + (transpose(a).asType(type),)
if len(cast_arrays) == 1:
return cast_arrays
else:
return cast_arrays

def _findLapackRoutine(name, type):
name = _lapack_letter[_lapack_type[type]] + name
module = 'lapack_' + name[:3]
exec 'import ' + module
module = eval(module)
return getattr(module, name)

def _assertRank2(*arrays):
for a in arrays:
if len(a.shape) != 2:
raise LinAlgError, 'Array must be two-dimensional'

def _assertSquareness(*arrays):
for a in arrays:
if max(a.shape) != min(a.shape):
raise LinAlgError, 'Array must be square'

# unit matrix

def _unitMatrix(n):
i = Numeric.arange(n)
return Numeric.equal(i[:,Numeric.NewAxis], i)

# A dot function behaving like matrix multiplication (for 2D arrays)

def _dot2(a1, a2):
return(Numeric.dot(a1,transpose(a2)))

# Singular value decomposition

def singularValueDecomposition(a):
_assertRank2(a)
n = a.shape
m = a.shape
t =_commonType(a)
real_t = _array_type[_array_precision[t]]
lapack_routine = _findLapackRoutine('gesvd', t)
a = _castCopyAndTranspose(t, a)
s = zeros((min(n,m),), real_t)
u = zeros((m,m,), t)
vt =zeros((n,n,), t)
lwork = 10*max(m,n) # minimum value: max(3*min(m,n)+max(m,n),5*min(m,n)-4)
work = zeros((lwork,), t)
if _array_kind[t] == 1: # Complex routines take different arguments
rwork = zeros((max(3*min(m,n),5*min(m,n)-4),), real_t)
results = lapack_routine('A', 'A', m, n, a, m, s, u, m, vt, n,
work, lwork, rwork, 0)
else:
results = lapack_routine('A', 'A', m, n, a, m, s, u, m, vt, n,
work, lwork, 0)
if results['info'] > 0:
raise LinAlgError, 'SVD did not converge'
return cp(transpose(u)), s, cp(transpose(vt))

# Generalized inverse

def generalizedInverse(a):
u, s, vt = singularValueDecomposition(a)
m = u.shape
n = vt.shape
cutoff = 1.e-10*Numeric.maximum.reduce(s)
sm = zeros((n,m,),s.typecode())
for i in range(min(n,m)):
if s[i] > cutoff:
sm[i,i] = 1./s[i]
return _dot2(_dot2(transpose(vt), sm), transpose(u))

# Linear equations

def solveLinearEquations(a, b):
one_eq = len(b.shape) == 1
if one_eq:
b = b[:, Numeric.NewAxis]
_assertRank2(a, b)
_assertSquareness(a)
n_eq = a.shape
n_rhs = b.shape
if n_eq != b.shape:
raise LinAlgError, 'Incompatible dimensions'
t =_commonType(a, b)
lapack_routine = _findLapackRoutine('gesv', t)
a, b = _castCopyAndTranspose(t, a, b)
pivots = zeros((n_eq,), 'l')
results = lapack_routine(n_eq, n_rhs, a, n_eq, pivots, b, n_eq, 0)
if results['info'] > 0:
raise LinAlgError, 'Singular matrix'
if one_eq:
return cp(Numeric.ravel(b))
else:
return cp(transpose(b))

# Matrix inversion

def inverse(a):
return solveLinearEquations(a, _unitMatrix(a.shape))

# Eigenvalues

def eigenvalues(a):
_assertRank2(a)
_assertSquareness(a)
t =_commonType(a)
real_t = _array_type[_array_precision[t]]
lapack_routine = _findLapackRoutine('geev', t)
a = _castCopyAndTranspose(t, a)
n = a.shape
dummy = Numeric.zeros((1,), t)
lwork = max(1,6*n) # minimum value: max(1,3*n) real, max(1,2*n) complex
work = Numeric.zeros((lwork,), t)
if _array_kind[t] == 1: # Complex routines take different arguments
w = Numeric.zeros((n,), t)
rwork = Numeric.zeros((n,),real_t)
results = lapack_routine('N', 'N', n, a, n, w,
dummy, 1, dummy, 1, work, lwork, rwork, 0)
else:
wr = Numeric.zeros((n,), t)
wi = Numeric.zeros((n,), t)
results = lapack_routine('N', 'N', n, a, n, wr, wi,
dummy, 1, dummy, 1, work, lwork, 0)
if Numeric.logicalAnd.reduce(Numeric.equal(wi, 0.)):
w = wr
else:
w = wr+1j*wi
if results['info'] > 0:
raise LinAlgError, 'Eigenvalues did not converge'
return w

=================
MATRIX-SIG  - SIG on Matrix Math for Python

send messages to: matrix-sig@python.org