Spaces:
Sleeping
Sleeping
""" | |
Linear algebra | |
-------------- | |
Linear equations | |
................ | |
Basic linear algebra is implemented; you can for example solve the linear | |
equation system:: | |
x + 2*y = -10 | |
3*x + 4*y = 10 | |
using ``lu_solve``:: | |
>>> from mpmath import * | |
>>> mp.pretty = False | |
>>> A = matrix([[1, 2], [3, 4]]) | |
>>> b = matrix([-10, 10]) | |
>>> x = lu_solve(A, b) | |
>>> x | |
matrix( | |
[['30.0'], | |
['-20.0']]) | |
If you don't trust the result, use ``residual`` to calculate the residual ||A*x-b||:: | |
>>> residual(A, x, b) | |
matrix( | |
[['3.46944695195361e-18'], | |
['3.46944695195361e-18']]) | |
>>> str(eps) | |
'2.22044604925031e-16' | |
As you can see, the solution is quite accurate. The error is caused by the | |
inaccuracy of the internal floating point arithmetic. Though, it's even smaller | |
than the current machine epsilon, which basically means you can trust the | |
result. | |
If you need more speed, use NumPy, or ``fp.lu_solve`` for a floating-point computation. | |
>>> fp.lu_solve(A, b) # doctest: +ELLIPSIS | |
matrix(...) | |
``lu_solve`` accepts overdetermined systems. It is usually not possible to solve | |
such systems, so the residual is minimized instead. Internally this is done | |
using Cholesky decomposition to compute a least squares approximation. This means | |
that that ``lu_solve`` will square the errors. If you can't afford this, use | |
``qr_solve`` instead. It is twice as slow but more accurate, and it calculates | |
the residual automatically. | |
Matrix factorization | |
.................... | |
The function ``lu`` computes an explicit LU factorization of a matrix:: | |
>>> P, L, U = lu(matrix([[0,2,3],[4,5,6],[7,8,9]])) | |
>>> print(P) | |
[0.0 0.0 1.0] | |
[1.0 0.0 0.0] | |
[0.0 1.0 0.0] | |
>>> print(L) | |
[ 1.0 0.0 0.0] | |
[ 0.0 1.0 0.0] | |
[0.571428571428571 0.214285714285714 1.0] | |
>>> print(U) | |
[7.0 8.0 9.0] | |
[0.0 2.0 3.0] | |
[0.0 0.0 0.214285714285714] | |
>>> print(P.T*L*U) | |
[0.0 2.0 3.0] | |
[4.0 5.0 6.0] | |
[7.0 8.0 9.0] | |
Interval matrices | |
----------------- | |
Matrices may contain interval elements. This allows one to perform | |
basic linear algebra operations such as matrix multiplication | |
and equation solving with rigorous error bounds:: | |
>>> a = iv.matrix([['0.1','0.3','1.0'], | |
... ['7.1','5.5','4.8'], | |
... ['3.2','4.4','5.6']]) | |
>>> | |
>>> b = iv.matrix(['4','0.6','0.5']) | |
>>> c = iv.lu_solve(a, b) | |
>>> print(c) | |
[ [5.2582327113062568605927528666, 5.25823271130625686059275702219]] | |
[[-13.1550493962678375411635581388, -13.1550493962678375411635540152]] | |
[ [7.42069154774972557628979076189, 7.42069154774972557628979190734]] | |
>>> print(a*c) | |
[ [3.99999999999999999999999844904, 4.00000000000000000000000155096]] | |
[[0.599999999999999999999968898009, 0.600000000000000000000031763736]] | |
[[0.499999999999999999999979320485, 0.500000000000000000000020679515]] | |
""" | |
# TODO: | |
# *implement high-level qr() | |
# *test unitvector | |
# *iterative solving | |
from copy import copy | |
from ..libmp.backend import xrange | |
class LinearAlgebraMethods(object): | |
def LU_decomp(ctx, A, overwrite=False, use_cache=True): | |
""" | |
LU-factorization of a n*n matrix using the Gauss algorithm. | |
Returns L and U in one matrix and the pivot indices. | |
Use overwrite to specify whether A will be overwritten with L and U. | |
""" | |
if not A.rows == A.cols: | |
raise ValueError('need n*n matrix') | |
# get from cache if possible | |
if use_cache and isinstance(A, ctx.matrix) and A._LU: | |
return A._LU | |
if not overwrite: | |
orig = A | |
A = A.copy() | |
tol = ctx.absmin(ctx.mnorm(A,1) * ctx.eps) # each pivot element has to be bigger | |
n = A.rows | |
p = [None]*(n - 1) | |
for j in xrange(n - 1): | |
# pivoting, choose max(abs(reciprocal row sum)*abs(pivot element)) | |
biggest = 0 | |
for k in xrange(j, n): | |
s = ctx.fsum([ctx.absmin(A[k,l]) for l in xrange(j, n)]) | |
if ctx.absmin(s) <= tol: | |
raise ZeroDivisionError('matrix is numerically singular') | |
current = 1/s * ctx.absmin(A[k,j]) | |
if current > biggest: # TODO: what if equal? | |
biggest = current | |
p[j] = k | |
# swap rows according to p | |
ctx.swap_row(A, j, p[j]) | |
if ctx.absmin(A[j,j]) <= tol: | |
raise ZeroDivisionError('matrix is numerically singular') | |
# calculate elimination factors and add rows | |
for i in xrange(j + 1, n): | |
A[i,j] /= A[j,j] | |
for k in xrange(j + 1, n): | |
A[i,k] -= A[i,j]*A[j,k] | |
if ctx.absmin(A[n - 1,n - 1]) <= tol: | |
raise ZeroDivisionError('matrix is numerically singular') | |
# cache decomposition | |
if not overwrite and isinstance(orig, ctx.matrix): | |
orig._LU = (A, p) | |
return A, p | |
def L_solve(ctx, L, b, p=None): | |
""" | |
Solve the lower part of a LU factorized matrix for y. | |
""" | |
if L.rows != L.cols: | |
raise RuntimeError("need n*n matrix") | |
n = L.rows | |
if len(b) != n: | |
raise ValueError("Value should be equal to n") | |
b = copy(b) | |
if p: # swap b according to p | |
for k in xrange(0, len(p)): | |
ctx.swap_row(b, k, p[k]) | |
# solve | |
for i in xrange(1, n): | |
for j in xrange(i): | |
b[i] -= L[i,j] * b[j] | |
return b | |
def U_solve(ctx, U, y): | |
""" | |
Solve the upper part of a LU factorized matrix for x. | |
""" | |
if U.rows != U.cols: | |
raise RuntimeError("need n*n matrix") | |
n = U.rows | |
if len(y) != n: | |
raise ValueError("Value should be equal to n") | |
x = copy(y) | |
for i in xrange(n - 1, -1, -1): | |
for j in xrange(i + 1, n): | |
x[i] -= U[i,j] * x[j] | |
x[i] /= U[i,i] | |
return x | |
def lu_solve(ctx, A, b, **kwargs): | |
""" | |
Ax = b => x | |
Solve a determined or overdetermined linear equations system. | |
Fast LU decomposition is used, which is less accurate than QR decomposition | |
(especially for overdetermined systems), but it's twice as efficient. | |
Use qr_solve if you want more precision or have to solve a very ill- | |
conditioned system. | |
If you specify real=True, it does not check for overdeterminded complex | |
systems. | |
""" | |
prec = ctx.prec | |
try: | |
ctx.prec += 10 | |
# do not overwrite A nor b | |
A, b = ctx.matrix(A, **kwargs).copy(), ctx.matrix(b, **kwargs).copy() | |
if A.rows < A.cols: | |
raise ValueError('cannot solve underdetermined system') | |
if A.rows > A.cols: | |
# use least-squares method if overdetermined | |
# (this increases errors) | |
AH = A.H | |
A = AH * A | |
b = AH * b | |
if (kwargs.get('real', False) or | |
not sum(type(i) is ctx.mpc for i in A)): | |
# TODO: necessary to check also b? | |
x = ctx.cholesky_solve(A, b) | |
else: | |
x = ctx.lu_solve(A, b) | |
else: | |
# LU factorization | |
A, p = ctx.LU_decomp(A) | |
b = ctx.L_solve(A, b, p) | |
x = ctx.U_solve(A, b) | |
finally: | |
ctx.prec = prec | |
return x | |
def improve_solution(ctx, A, x, b, maxsteps=1): | |
""" | |
Improve a solution to a linear equation system iteratively. | |
This re-uses the LU decomposition and is thus cheap. | |
Usually 3 up to 4 iterations are giving the maximal improvement. | |
""" | |
if A.rows != A.cols: | |
raise RuntimeError("need n*n matrix") # TODO: really? | |
for _ in xrange(maxsteps): | |
r = ctx.residual(A, x, b) | |
if ctx.norm(r, 2) < 10*ctx.eps: | |
break | |
# this uses cached LU decomposition and is thus cheap | |
dx = ctx.lu_solve(A, -r) | |
x += dx | |
return x | |
def lu(ctx, A): | |
""" | |
A -> P, L, U | |
LU factorisation of a square matrix A. L is the lower, U the upper part. | |
P is the permutation matrix indicating the row swaps. | |
P*A = L*U | |
If you need efficiency, use the low-level method LU_decomp instead, it's | |
much more memory efficient. | |
""" | |
# get factorization | |
A, p = ctx.LU_decomp(A) | |
n = A.rows | |
L = ctx.matrix(n) | |
U = ctx.matrix(n) | |
for i in xrange(n): | |
for j in xrange(n): | |
if i > j: | |
L[i,j] = A[i,j] | |
elif i == j: | |
L[i,j] = 1 | |
U[i,j] = A[i,j] | |
else: | |
U[i,j] = A[i,j] | |
# calculate permutation matrix | |
P = ctx.eye(n) | |
for k in xrange(len(p)): | |
ctx.swap_row(P, k, p[k]) | |
return P, L, U | |
def unitvector(ctx, n, i): | |
""" | |
Return the i-th n-dimensional unit vector. | |
""" | |
assert 0 < i <= n, 'this unit vector does not exist' | |
return [ctx.zero]*(i-1) + [ctx.one] + [ctx.zero]*(n-i) | |
def inverse(ctx, A, **kwargs): | |
""" | |
Calculate the inverse of a matrix. | |
If you want to solve an equation system Ax = b, it's recommended to use | |
solve(A, b) instead, it's about 3 times more efficient. | |
""" | |
prec = ctx.prec | |
try: | |
ctx.prec += 10 | |
# do not overwrite A | |
A = ctx.matrix(A, **kwargs).copy() | |
n = A.rows | |
# get LU factorisation | |
A, p = ctx.LU_decomp(A) | |
cols = [] | |
# calculate unit vectors and solve corresponding system to get columns | |
for i in xrange(1, n + 1): | |
e = ctx.unitvector(n, i) | |
y = ctx.L_solve(A, e, p) | |
cols.append(ctx.U_solve(A, y)) | |
# convert columns to matrix | |
inv = [] | |
for i in xrange(n): | |
row = [] | |
for j in xrange(n): | |
row.append(cols[j][i]) | |
inv.append(row) | |
result = ctx.matrix(inv, **kwargs) | |
finally: | |
ctx.prec = prec | |
return result | |
def householder(ctx, A): | |
""" | |
(A|b) -> H, p, x, res | |
(A|b) is the coefficient matrix with left hand side of an optionally | |
overdetermined linear equation system. | |
H and p contain all information about the transformation matrices. | |
x is the solution, res the residual. | |
""" | |
if not isinstance(A, ctx.matrix): | |
raise TypeError("A should be a type of ctx.matrix") | |
m = A.rows | |
n = A.cols | |
if m < n - 1: | |
raise RuntimeError("Columns should not be less than rows") | |
# calculate Householder matrix | |
p = [] | |
for j in xrange(0, n - 1): | |
s = ctx.fsum(abs(A[i,j])**2 for i in xrange(j, m)) | |
if not abs(s) > ctx.eps: | |
raise ValueError('matrix is numerically singular') | |
p.append(-ctx.sign(ctx.re(A[j,j])) * ctx.sqrt(s)) | |
kappa = ctx.one / (s - p[j] * A[j,j]) | |
A[j,j] -= p[j] | |
for k in xrange(j+1, n): | |
y = ctx.fsum(ctx.conj(A[i,j]) * A[i,k] for i in xrange(j, m)) * kappa | |
for i in xrange(j, m): | |
A[i,k] -= A[i,j] * y | |
# solve Rx = c1 | |
x = [A[i,n - 1] for i in xrange(n - 1)] | |
for i in xrange(n - 2, -1, -1): | |
x[i] -= ctx.fsum(A[i,j] * x[j] for j in xrange(i + 1, n - 1)) | |
x[i] /= p[i] | |
# calculate residual | |
if not m == n - 1: | |
r = [A[m-1-i, n-1] for i in xrange(m - n + 1)] | |
else: | |
# determined system, residual should be 0 | |
r = [0]*m # maybe a bad idea, changing r[i] will change all elements | |
return A, p, x, r | |
#def qr(ctx, A): | |
# """ | |
# A -> Q, R | |
# | |
# QR factorisation of a square matrix A using Householder decomposition. | |
# Q is orthogonal, this leads to very few numerical errors. | |
# | |
# A = Q*R | |
# """ | |
# H, p, x, res = householder(A) | |
# TODO: implement this | |
def residual(ctx, A, x, b, **kwargs): | |
""" | |
Calculate the residual of a solution to a linear equation system. | |
r = A*x - b for A*x = b | |
""" | |
oldprec = ctx.prec | |
try: | |
ctx.prec *= 2 | |
A, x, b = ctx.matrix(A, **kwargs), ctx.matrix(x, **kwargs), ctx.matrix(b, **kwargs) | |
return A*x - b | |
finally: | |
ctx.prec = oldprec | |
def qr_solve(ctx, A, b, norm=None, **kwargs): | |
""" | |
Ax = b => x, ||Ax - b|| | |
Solve a determined or overdetermined linear equations system and | |
calculate the norm of the residual (error). | |
QR decomposition using Householder factorization is applied, which gives very | |
accurate results even for ill-conditioned matrices. qr_solve is twice as | |
efficient. | |
""" | |
if norm is None: | |
norm = ctx.norm | |
prec = ctx.prec | |
try: | |
ctx.prec += 10 | |
# do not overwrite A nor b | |
A, b = ctx.matrix(A, **kwargs).copy(), ctx.matrix(b, **kwargs).copy() | |
if A.rows < A.cols: | |
raise ValueError('cannot solve underdetermined system') | |
H, p, x, r = ctx.householder(ctx.extend(A, b)) | |
res = ctx.norm(r) | |
# calculate residual "manually" for determined systems | |
if res == 0: | |
res = ctx.norm(ctx.residual(A, x, b)) | |
return ctx.matrix(x, **kwargs), res | |
finally: | |
ctx.prec = prec | |
def cholesky(ctx, A, tol=None): | |
r""" | |
Cholesky decomposition of a symmetric positive-definite matrix `A`. | |
Returns a lower triangular matrix `L` such that `A = L \times L^T`. | |
More generally, for a complex Hermitian positive-definite matrix, | |
a Cholesky decomposition satisfying `A = L \times L^H` is returned. | |
The Cholesky decomposition can be used to solve linear equation | |
systems twice as efficiently as LU decomposition, or to | |
test whether `A` is positive-definite. | |
The optional parameter ``tol`` determines the tolerance for | |
verifying positive-definiteness. | |
**Examples** | |
Cholesky decomposition of a positive-definite symmetric matrix:: | |
>>> from mpmath import * | |
>>> mp.dps = 25; mp.pretty = True | |
>>> A = eye(3) + hilbert(3) | |
>>> nprint(A) | |
[ 2.0 0.5 0.333333] | |
[ 0.5 1.33333 0.25] | |
[0.333333 0.25 1.2] | |
>>> L = cholesky(A) | |
>>> nprint(L) | |
[ 1.41421 0.0 0.0] | |
[0.353553 1.09924 0.0] | |
[0.235702 0.15162 1.05899] | |
>>> chop(A - L*L.T) | |
[0.0 0.0 0.0] | |
[0.0 0.0 0.0] | |
[0.0 0.0 0.0] | |
Cholesky decomposition of a Hermitian matrix:: | |
>>> A = eye(3) + matrix([[0,0.25j,-0.5j],[-0.25j,0,0],[0.5j,0,0]]) | |
>>> L = cholesky(A) | |
>>> nprint(L) | |
[ 1.0 0.0 0.0] | |
[(0.0 - 0.25j) (0.968246 + 0.0j) 0.0] | |
[ (0.0 + 0.5j) (0.129099 + 0.0j) (0.856349 + 0.0j)] | |
>>> chop(A - L*L.H) | |
[0.0 0.0 0.0] | |
[0.0 0.0 0.0] | |
[0.0 0.0 0.0] | |
Attempted Cholesky decomposition of a matrix that is not positive | |
definite:: | |
>>> A = -eye(3) + hilbert(3) | |
>>> L = cholesky(A) | |
Traceback (most recent call last): | |
... | |
ValueError: matrix is not positive-definite | |
**References** | |
1. [Wikipedia]_ http://en.wikipedia.org/wiki/Cholesky_decomposition | |
""" | |
if not isinstance(A, ctx.matrix): | |
raise RuntimeError("A should be a type of ctx.matrix") | |
if not A.rows == A.cols: | |
raise ValueError('need n*n matrix') | |
if tol is None: | |
tol = +ctx.eps | |
n = A.rows | |
L = ctx.matrix(n) | |
for j in xrange(n): | |
c = ctx.re(A[j,j]) | |
if abs(c-A[j,j]) > tol: | |
raise ValueError('matrix is not Hermitian') | |
s = c - ctx.fsum((L[j,k] for k in xrange(j)), | |
absolute=True, squared=True) | |
if s < tol: | |
raise ValueError('matrix is not positive-definite') | |
L[j,j] = ctx.sqrt(s) | |
for i in xrange(j, n): | |
it1 = (L[i,k] for k in xrange(j)) | |
it2 = (L[j,k] for k in xrange(j)) | |
t = ctx.fdot(it1, it2, conjugate=True) | |
L[i,j] = (A[i,j] - t) / L[j,j] | |
return L | |
def cholesky_solve(ctx, A, b, **kwargs): | |
""" | |
Ax = b => x | |
Solve a symmetric positive-definite linear equation system. | |
This is twice as efficient as lu_solve. | |
Typical use cases: | |
* A.T*A | |
* Hessian matrix | |
* differential equations | |
""" | |
prec = ctx.prec | |
try: | |
ctx.prec += 10 | |
# do not overwrite A nor b | |
A, b = ctx.matrix(A, **kwargs).copy(), ctx.matrix(b, **kwargs).copy() | |
if A.rows != A.cols: | |
raise ValueError('can only solve determined system') | |
# Cholesky factorization | |
L = ctx.cholesky(A) | |
# solve | |
n = L.rows | |
if len(b) != n: | |
raise ValueError("Value should be equal to n") | |
for i in xrange(n): | |
b[i] -= ctx.fsum(L[i,j] * b[j] for j in xrange(i)) | |
b[i] /= L[i,i] | |
x = ctx.U_solve(L.T, b) | |
return x | |
finally: | |
ctx.prec = prec | |
def det(ctx, A): | |
""" | |
Calculate the determinant of a matrix. | |
""" | |
prec = ctx.prec | |
try: | |
# do not overwrite A | |
A = ctx.matrix(A).copy() | |
# use LU factorization to calculate determinant | |
try: | |
R, p = ctx.LU_decomp(A) | |
except ZeroDivisionError: | |
return 0 | |
z = 1 | |
for i, e in enumerate(p): | |
if i != e: | |
z *= -1 | |
for i in xrange(A.rows): | |
z *= R[i,i] | |
return z | |
finally: | |
ctx.prec = prec | |
def cond(ctx, A, norm=None): | |
""" | |
Calculate the condition number of a matrix using a specified matrix norm. | |
The condition number estimates the sensitivity of a matrix to errors. | |
Example: small input errors for ill-conditioned coefficient matrices | |
alter the solution of the system dramatically. | |
For ill-conditioned matrices it's recommended to use qr_solve() instead | |
of lu_solve(). This does not help with input errors however, it just avoids | |
to add additional errors. | |
Definition: cond(A) = ||A|| * ||A**-1|| | |
""" | |
if norm is None: | |
norm = lambda x: ctx.mnorm(x,1) | |
return norm(A) * norm(ctx.inverse(A)) | |
def lu_solve_mat(ctx, a, b): | |
"""Solve a * x = b where a and b are matrices.""" | |
r = ctx.matrix(a.rows, b.cols) | |
for i in range(b.cols): | |
c = ctx.lu_solve(a, b.column(i)) | |
for j in range(len(c)): | |
r[j, i] = c[j] | |
return r | |
def qr(ctx, A, mode = 'full', edps = 10): | |
""" | |
Compute a QR factorization $A = QR$ where | |
A is an m x n matrix of real or complex numbers where m >= n | |
mode has following meanings: | |
(1) mode = 'raw' returns two matrixes (A, tau) in the | |
internal format used by LAPACK | |
(2) mode = 'skinny' returns the leading n columns of Q | |
and n rows of R | |
(3) Any other value returns the leading m columns of Q | |
and m rows of R | |
edps is the increase in mp precision used for calculations | |
**Examples** | |
>>> from mpmath import * | |
>>> mp.dps = 15 | |
>>> mp.pretty = True | |
>>> A = matrix([[1, 2], [3, 4], [1, 1]]) | |
>>> Q, R = qr(A) | |
>>> Q | |
[-0.301511344577764 0.861640436855329 0.408248290463863] | |
[-0.904534033733291 -0.123091490979333 -0.408248290463863] | |
[-0.301511344577764 -0.492365963917331 0.816496580927726] | |
>>> R | |
[-3.3166247903554 -4.52267016866645] | |
[ 0.0 0.738548945875996] | |
[ 0.0 0.0] | |
>>> Q * R | |
[1.0 2.0] | |
[3.0 4.0] | |
[1.0 1.0] | |
>>> chop(Q.T * Q) | |
[1.0 0.0 0.0] | |
[0.0 1.0 0.0] | |
[0.0 0.0 1.0] | |
>>> B = matrix([[1+0j, 2-3j], [3+j, 4+5j]]) | |
>>> Q, R = qr(B) | |
>>> nprint(Q) | |
[ (-0.301511 + 0.0j) (0.0695795 - 0.95092j)] | |
[(-0.904534 - 0.301511j) (-0.115966 + 0.278318j)] | |
>>> nprint(R) | |
[(-3.31662 + 0.0j) (-5.72872 - 2.41209j)] | |
[ 0.0 (3.91965 + 0.0j)] | |
>>> Q * R | |
[(1.0 + 0.0j) (2.0 - 3.0j)] | |
[(3.0 + 1.0j) (4.0 + 5.0j)] | |
>>> chop(Q.T * Q.conjugate()) | |
[1.0 0.0] | |
[0.0 1.0] | |
""" | |
# check values before continuing | |
assert isinstance(A, ctx.matrix) | |
m = A.rows | |
n = A.cols | |
assert n >= 0 | |
assert m >= n | |
assert edps >= 0 | |
# check for complex data type | |
cmplx = any(type(x) is ctx.mpc for x in A) | |
# temporarily increase the precision and initialize | |
with ctx.extradps(edps): | |
tau = ctx.matrix(n,1) | |
A = A.copy() | |
# --------------- | |
# FACTOR MATRIX A | |
# --------------- | |
if cmplx: | |
one = ctx.mpc('1.0', '0.0') | |
zero = ctx.mpc('0.0', '0.0') | |
rzero = ctx.mpf('0.0') | |
# main loop to factor A (complex) | |
for j in xrange(0, n): | |
alpha = A[j,j] | |
alphr = ctx.re(alpha) | |
alphi = ctx.im(alpha) | |
if (m-j) >= 2: | |
xnorm = ctx.fsum( A[i,j]*ctx.conj(A[i,j]) for i in xrange(j+1, m) ) | |
xnorm = ctx.re( ctx.sqrt(xnorm) ) | |
else: | |
xnorm = rzero | |
if (xnorm == rzero) and (alphi == rzero): | |
tau[j] = zero | |
continue | |
if alphr < rzero: | |
beta = ctx.sqrt(alphr**2 + alphi**2 + xnorm**2) | |
else: | |
beta = -ctx.sqrt(alphr**2 + alphi**2 + xnorm**2) | |
tau[j] = ctx.mpc( (beta - alphr) / beta, -alphi / beta ) | |
t = -ctx.conj(tau[j]) | |
za = one / (alpha - beta) | |
for i in xrange(j+1, m): | |
A[i,j] *= za | |
A[j,j] = one | |
for k in xrange(j+1, n): | |
y = ctx.fsum(A[i,j] * ctx.conj(A[i,k]) for i in xrange(j, m)) | |
temp = t * ctx.conj(y) | |
for i in xrange(j, m): | |
A[i,k] += A[i,j] * temp | |
A[j,j] = ctx.mpc(beta, '0.0') | |
else: | |
one = ctx.mpf('1.0') | |
zero = ctx.mpf('0.0') | |
# main loop to factor A (real) | |
for j in xrange(0, n): | |
alpha = A[j,j] | |
if (m-j) > 2: | |
xnorm = ctx.fsum( (A[i,j])**2 for i in xrange(j+1, m) ) | |
xnorm = ctx.sqrt(xnorm) | |
elif (m-j) == 2: | |
xnorm = abs( A[m-1,j] ) | |
else: | |
xnorm = zero | |
if xnorm == zero: | |
tau[j] = zero | |
continue | |
if alpha < zero: | |
beta = ctx.sqrt(alpha**2 + xnorm**2) | |
else: | |
beta = -ctx.sqrt(alpha**2 + xnorm**2) | |
tau[j] = (beta - alpha) / beta | |
t = -tau[j] | |
da = one / (alpha - beta) | |
for i in xrange(j+1, m): | |
A[i,j] *= da | |
A[j,j] = one | |
for k in xrange(j+1, n): | |
y = ctx.fsum( A[i,j] * A[i,k] for i in xrange(j, m) ) | |
temp = t * y | |
for i in xrange(j,m): | |
A[i,k] += A[i,j] * temp | |
A[j,j] = beta | |
# return factorization in same internal format as LAPACK | |
if (mode == 'raw') or (mode == 'RAW'): | |
return A, tau | |
# ---------------------------------- | |
# FORM Q USING BACKWARD ACCUMULATION | |
# ---------------------------------- | |
# form R before the values are overwritten | |
R = A.copy() | |
for j in xrange(0, n): | |
for i in xrange(j+1, m): | |
R[i,j] = zero | |
# set the value of p (number of columns of Q to return) | |
p = m | |
if (mode == 'skinny') or (mode == 'SKINNY'): | |
p = n | |
# add columns to A if needed and initialize | |
A.cols += (p-n) | |
for j in xrange(0, p): | |
A[j,j] = one | |
for i in xrange(0, j): | |
A[i,j] = zero | |
# main loop to form Q | |
for j in xrange(n-1, -1, -1): | |
t = -tau[j] | |
A[j,j] += t | |
for k in xrange(j+1, p): | |
if cmplx: | |
y = ctx.fsum(A[i,j] * ctx.conj(A[i,k]) for i in xrange(j+1, m)) | |
temp = t * ctx.conj(y) | |
else: | |
y = ctx.fsum(A[i,j] * A[i,k] for i in xrange(j+1, m)) | |
temp = t * y | |
A[j,k] = temp | |
for i in xrange(j+1, m): | |
A[i,k] += A[i,j] * temp | |
for i in xrange(j+1, m): | |
A[i, j] *= t | |
return A, R[0:p,0:n] | |
# ------------------ | |
# END OF FUNCTION QR | |
# ------------------ | |