Fixed database typo and removed unnecessary class identifier.
This commit is contained in:
parent
00ad49a143
commit
45fb349a7d
5098 changed files with 952558 additions and 85 deletions
|
@ -0,0 +1,405 @@
|
|||
"""Basic linear factorizations needed by the solver."""
|
||||
|
||||
from scipy.sparse import (bmat, csc_matrix, eye, issparse)
|
||||
from scipy.sparse.linalg import LinearOperator
|
||||
import scipy.linalg
|
||||
import scipy.sparse.linalg
|
||||
try:
|
||||
from sksparse.cholmod import cholesky_AAt
|
||||
sksparse_available = True
|
||||
except ImportError:
|
||||
import warnings
|
||||
sksparse_available = False
|
||||
import numpy as np
|
||||
from warnings import warn
|
||||
|
||||
__all__ = [
|
||||
'orthogonality',
|
||||
'projections',
|
||||
]
|
||||
|
||||
|
||||
def orthogonality(A, g):
|
||||
"""Measure orthogonality between a vector and the null space of a matrix.
|
||||
|
||||
Compute a measure of orthogonality between the null space
|
||||
of the (possibly sparse) matrix ``A`` and a given vector ``g``.
|
||||
|
||||
The formula is a simplified (and cheaper) version of formula (3.13)
|
||||
from [1]_.
|
||||
``orth = norm(A g, ord=2)/(norm(A, ord='fro')*norm(g, ord=2))``.
|
||||
|
||||
References
|
||||
----------
|
||||
.. [1] Gould, Nicholas IM, Mary E. Hribar, and Jorge Nocedal.
|
||||
"On the solution of equality constrained quadratic
|
||||
programming problems arising in optimization."
|
||||
SIAM Journal on Scientific Computing 23.4 (2001): 1376-1395.
|
||||
"""
|
||||
# Compute vector norms
|
||||
norm_g = np.linalg.norm(g)
|
||||
# Compute Froebnius norm of the matrix A
|
||||
if issparse(A):
|
||||
norm_A = scipy.sparse.linalg.norm(A, ord='fro')
|
||||
else:
|
||||
norm_A = np.linalg.norm(A, ord='fro')
|
||||
|
||||
# Check if norms are zero
|
||||
if norm_g == 0 or norm_A == 0:
|
||||
return 0
|
||||
|
||||
norm_A_g = np.linalg.norm(A.dot(g))
|
||||
# Orthogonality measure
|
||||
orth = norm_A_g / (norm_A*norm_g)
|
||||
return orth
|
||||
|
||||
|
||||
def normal_equation_projections(A, m, n, orth_tol, max_refin, tol):
|
||||
"""Return linear operators for matrix A using ``NormalEquation`` approach.
|
||||
"""
|
||||
# Cholesky factorization
|
||||
factor = cholesky_AAt(A)
|
||||
|
||||
# z = x - A.T inv(A A.T) A x
|
||||
def null_space(x):
|
||||
v = factor(A.dot(x))
|
||||
z = x - A.T.dot(v)
|
||||
|
||||
# Iterative refinement to improve roundoff
|
||||
# errors described in [2]_, algorithm 5.1.
|
||||
k = 0
|
||||
while orthogonality(A, z) > orth_tol:
|
||||
if k >= max_refin:
|
||||
break
|
||||
# z_next = z - A.T inv(A A.T) A z
|
||||
v = factor(A.dot(z))
|
||||
z = z - A.T.dot(v)
|
||||
k += 1
|
||||
|
||||
return z
|
||||
|
||||
# z = inv(A A.T) A x
|
||||
def least_squares(x):
|
||||
return factor(A.dot(x))
|
||||
|
||||
# z = A.T inv(A A.T) x
|
||||
def row_space(x):
|
||||
return A.T.dot(factor(x))
|
||||
|
||||
return null_space, least_squares, row_space
|
||||
|
||||
|
||||
def augmented_system_projections(A, m, n, orth_tol, max_refin, tol):
|
||||
"""Return linear operators for matrix A - ``AugmentedSystem``."""
|
||||
# Form augmented system
|
||||
K = csc_matrix(bmat([[eye(n), A.T], [A, None]]))
|
||||
# LU factorization
|
||||
# TODO: Use a symmetric indefinite factorization
|
||||
# to solve the system twice as fast (because
|
||||
# of the symmetry).
|
||||
try:
|
||||
solve = scipy.sparse.linalg.factorized(K)
|
||||
except RuntimeError:
|
||||
warn("Singular Jacobian matrix. Using dense SVD decomposition to "
|
||||
"perform the factorizations.")
|
||||
return svd_factorization_projections(A.toarray(),
|
||||
m, n, orth_tol,
|
||||
max_refin, tol)
|
||||
|
||||
# z = x - A.T inv(A A.T) A x
|
||||
# is computed solving the extended system:
|
||||
# [I A.T] * [ z ] = [x]
|
||||
# [A O ] [aux] [0]
|
||||
def null_space(x):
|
||||
# v = [x]
|
||||
# [0]
|
||||
v = np.hstack([x, np.zeros(m)])
|
||||
# lu_sol = [ z ]
|
||||
# [aux]
|
||||
lu_sol = solve(v)
|
||||
z = lu_sol[:n]
|
||||
|
||||
# Iterative refinement to improve roundoff
|
||||
# errors described in [2]_, algorithm 5.2.
|
||||
k = 0
|
||||
while orthogonality(A, z) > orth_tol:
|
||||
if k >= max_refin:
|
||||
break
|
||||
# new_v = [x] - [I A.T] * [ z ]
|
||||
# [0] [A O ] [aux]
|
||||
new_v = v - K.dot(lu_sol)
|
||||
# [I A.T] * [delta z ] = new_v
|
||||
# [A O ] [delta aux]
|
||||
lu_update = solve(new_v)
|
||||
# [ z ] += [delta z ]
|
||||
# [aux] [delta aux]
|
||||
lu_sol += lu_update
|
||||
z = lu_sol[:n]
|
||||
k += 1
|
||||
|
||||
# return z = x - A.T inv(A A.T) A x
|
||||
return z
|
||||
|
||||
# z = inv(A A.T) A x
|
||||
# is computed solving the extended system:
|
||||
# [I A.T] * [aux] = [x]
|
||||
# [A O ] [ z ] [0]
|
||||
def least_squares(x):
|
||||
# v = [x]
|
||||
# [0]
|
||||
v = np.hstack([x, np.zeros(m)])
|
||||
# lu_sol = [aux]
|
||||
# [ z ]
|
||||
lu_sol = solve(v)
|
||||
# return z = inv(A A.T) A x
|
||||
return lu_sol[n:m+n]
|
||||
|
||||
# z = A.T inv(A A.T) x
|
||||
# is computed solving the extended system:
|
||||
# [I A.T] * [ z ] = [0]
|
||||
# [A O ] [aux] [x]
|
||||
def row_space(x):
|
||||
# v = [0]
|
||||
# [x]
|
||||
v = np.hstack([np.zeros(n), x])
|
||||
# lu_sol = [ z ]
|
||||
# [aux]
|
||||
lu_sol = solve(v)
|
||||
# return z = A.T inv(A A.T) x
|
||||
return lu_sol[:n]
|
||||
|
||||
return null_space, least_squares, row_space
|
||||
|
||||
|
||||
def qr_factorization_projections(A, m, n, orth_tol, max_refin, tol):
|
||||
"""Return linear operators for matrix A using ``QRFactorization`` approach.
|
||||
"""
|
||||
# QRFactorization
|
||||
Q, R, P = scipy.linalg.qr(A.T, pivoting=True, mode='economic')
|
||||
|
||||
if np.linalg.norm(R[-1, :], np.inf) < tol:
|
||||
warn('Singular Jacobian matrix. Using SVD decomposition to ' +
|
||||
'perform the factorizations.')
|
||||
return svd_factorization_projections(A, m, n,
|
||||
orth_tol,
|
||||
max_refin,
|
||||
tol)
|
||||
|
||||
# z = x - A.T inv(A A.T) A x
|
||||
def null_space(x):
|
||||
# v = P inv(R) Q.T x
|
||||
aux1 = Q.T.dot(x)
|
||||
aux2 = scipy.linalg.solve_triangular(R, aux1, lower=False)
|
||||
v = np.zeros(m)
|
||||
v[P] = aux2
|
||||
z = x - A.T.dot(v)
|
||||
|
||||
# Iterative refinement to improve roundoff
|
||||
# errors described in [2]_, algorithm 5.1.
|
||||
k = 0
|
||||
while orthogonality(A, z) > orth_tol:
|
||||
if k >= max_refin:
|
||||
break
|
||||
# v = P inv(R) Q.T x
|
||||
aux1 = Q.T.dot(z)
|
||||
aux2 = scipy.linalg.solve_triangular(R, aux1, lower=False)
|
||||
v[P] = aux2
|
||||
# z_next = z - A.T v
|
||||
z = z - A.T.dot(v)
|
||||
k += 1
|
||||
|
||||
return z
|
||||
|
||||
# z = inv(A A.T) A x
|
||||
def least_squares(x):
|
||||
# z = P inv(R) Q.T x
|
||||
aux1 = Q.T.dot(x)
|
||||
aux2 = scipy.linalg.solve_triangular(R, aux1, lower=False)
|
||||
z = np.zeros(m)
|
||||
z[P] = aux2
|
||||
return z
|
||||
|
||||
# z = A.T inv(A A.T) x
|
||||
def row_space(x):
|
||||
# z = Q inv(R.T) P.T x
|
||||
aux1 = x[P]
|
||||
aux2 = scipy.linalg.solve_triangular(R, aux1,
|
||||
lower=False,
|
||||
trans='T')
|
||||
z = Q.dot(aux2)
|
||||
return z
|
||||
|
||||
return null_space, least_squares, row_space
|
||||
|
||||
|
||||
def svd_factorization_projections(A, m, n, orth_tol, max_refin, tol):
|
||||
"""Return linear operators for matrix A using ``SVDFactorization`` approach.
|
||||
"""
|
||||
# SVD Factorization
|
||||
U, s, Vt = scipy.linalg.svd(A, full_matrices=False)
|
||||
|
||||
# Remove dimensions related with very small singular values
|
||||
U = U[:, s > tol]
|
||||
Vt = Vt[s > tol, :]
|
||||
s = s[s > tol]
|
||||
|
||||
# z = x - A.T inv(A A.T) A x
|
||||
def null_space(x):
|
||||
# v = U 1/s V.T x = inv(A A.T) A x
|
||||
aux1 = Vt.dot(x)
|
||||
aux2 = 1/s*aux1
|
||||
v = U.dot(aux2)
|
||||
z = x - A.T.dot(v)
|
||||
|
||||
# Iterative refinement to improve roundoff
|
||||
# errors described in [2]_, algorithm 5.1.
|
||||
k = 0
|
||||
while orthogonality(A, z) > orth_tol:
|
||||
if k >= max_refin:
|
||||
break
|
||||
# v = U 1/s V.T x = inv(A A.T) A x
|
||||
aux1 = Vt.dot(z)
|
||||
aux2 = 1/s*aux1
|
||||
v = U.dot(aux2)
|
||||
# z_next = z - A.T v
|
||||
z = z - A.T.dot(v)
|
||||
k += 1
|
||||
|
||||
return z
|
||||
|
||||
# z = inv(A A.T) A x
|
||||
def least_squares(x):
|
||||
# z = U 1/s V.T x = inv(A A.T) A x
|
||||
aux1 = Vt.dot(x)
|
||||
aux2 = 1/s*aux1
|
||||
z = U.dot(aux2)
|
||||
return z
|
||||
|
||||
# z = A.T inv(A A.T) x
|
||||
def row_space(x):
|
||||
# z = V 1/s U.T x
|
||||
aux1 = U.T.dot(x)
|
||||
aux2 = 1/s*aux1
|
||||
z = Vt.T.dot(aux2)
|
||||
return z
|
||||
|
||||
return null_space, least_squares, row_space
|
||||
|
||||
|
||||
def projections(A, method=None, orth_tol=1e-12, max_refin=3, tol=1e-15):
|
||||
"""Return three linear operators related with a given matrix A.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
A : sparse matrix (or ndarray), shape (m, n)
|
||||
Matrix ``A`` used in the projection.
|
||||
method : string, optional
|
||||
Method used for compute the given linear
|
||||
operators. Should be one of:
|
||||
|
||||
- 'NormalEquation': The operators
|
||||
will be computed using the
|
||||
so-called normal equation approach
|
||||
explained in [1]_. In order to do
|
||||
so the Cholesky factorization of
|
||||
``(A A.T)`` is computed. Exclusive
|
||||
for sparse matrices.
|
||||
- 'AugmentedSystem': The operators
|
||||
will be computed using the
|
||||
so-called augmented system approach
|
||||
explained in [1]_. Exclusive
|
||||
for sparse matrices.
|
||||
- 'QRFactorization': Compute projections
|
||||
using QR factorization. Exclusive for
|
||||
dense matrices.
|
||||
- 'SVDFactorization': Compute projections
|
||||
using SVD factorization. Exclusive for
|
||||
dense matrices.
|
||||
|
||||
orth_tol : float, optional
|
||||
Tolerance for iterative refinements.
|
||||
max_refin : int, optional
|
||||
Maximum number of iterative refinements.
|
||||
tol : float, optional
|
||||
Tolerance for singular values.
|
||||
|
||||
Returns
|
||||
-------
|
||||
Z : LinearOperator, shape (n, n)
|
||||
Null-space operator. For a given vector ``x``,
|
||||
the null space operator is equivalent to apply
|
||||
a projection matrix ``P = I - A.T inv(A A.T) A``
|
||||
to the vector. It can be shown that this is
|
||||
equivalent to project ``x`` into the null space
|
||||
of A.
|
||||
LS : LinearOperator, shape (m, n)
|
||||
Least-squares operator. For a given vector ``x``,
|
||||
the least-squares operator is equivalent to apply a
|
||||
pseudoinverse matrix ``pinv(A.T) = inv(A A.T) A``
|
||||
to the vector. It can be shown that this vector
|
||||
``pinv(A.T) x`` is the least_square solution to
|
||||
``A.T y = x``.
|
||||
Y : LinearOperator, shape (n, m)
|
||||
Row-space operator. For a given vector ``x``,
|
||||
the row-space operator is equivalent to apply a
|
||||
projection matrix ``Q = A.T inv(A A.T)``
|
||||
to the vector. It can be shown that this
|
||||
vector ``y = Q x`` the minimum norm solution
|
||||
of ``A y = x``.
|
||||
|
||||
Notes
|
||||
-----
|
||||
Uses iterative refinements described in [1]
|
||||
during the computation of ``Z`` in order to
|
||||
cope with the possibility of large roundoff errors.
|
||||
|
||||
References
|
||||
----------
|
||||
.. [1] Gould, Nicholas IM, Mary E. Hribar, and Jorge Nocedal.
|
||||
"On the solution of equality constrained quadratic
|
||||
programming problems arising in optimization."
|
||||
SIAM Journal on Scientific Computing 23.4 (2001): 1376-1395.
|
||||
"""
|
||||
m, n = np.shape(A)
|
||||
|
||||
# The factorization of an empty matrix
|
||||
# only works for the sparse representation.
|
||||
if m*n == 0:
|
||||
A = csc_matrix(A)
|
||||
|
||||
# Check Argument
|
||||
if issparse(A):
|
||||
if method is None:
|
||||
method = "AugmentedSystem"
|
||||
if method not in ("NormalEquation", "AugmentedSystem"):
|
||||
raise ValueError("Method not allowed for sparse matrix.")
|
||||
if method == "NormalEquation" and not sksparse_available:
|
||||
warnings.warn(("Only accepts 'NormalEquation' option when"
|
||||
" scikit-sparse is available. Using "
|
||||
"'AugmentedSystem' option instead."),
|
||||
ImportWarning)
|
||||
method = 'AugmentedSystem'
|
||||
else:
|
||||
if method is None:
|
||||
method = "QRFactorization"
|
||||
if method not in ("QRFactorization", "SVDFactorization"):
|
||||
raise ValueError("Method not allowed for dense array.")
|
||||
|
||||
if method == 'NormalEquation':
|
||||
null_space, least_squares, row_space \
|
||||
= normal_equation_projections(A, m, n, orth_tol, max_refin, tol)
|
||||
elif method == 'AugmentedSystem':
|
||||
null_space, least_squares, row_space \
|
||||
= augmented_system_projections(A, m, n, orth_tol, max_refin, tol)
|
||||
elif method == "QRFactorization":
|
||||
null_space, least_squares, row_space \
|
||||
= qr_factorization_projections(A, m, n, orth_tol, max_refin, tol)
|
||||
elif method == "SVDFactorization":
|
||||
null_space, least_squares, row_space \
|
||||
= svd_factorization_projections(A, m, n, orth_tol, max_refin, tol)
|
||||
|
||||
Z = LinearOperator((n, n), null_space)
|
||||
LS = LinearOperator((m, n), least_squares)
|
||||
Y = LinearOperator((n, m), row_space)
|
||||
|
||||
return Z, LS, Y
|
Loading…
Add table
Add a link
Reference in a new issue