Skip to content

Commit 21c3acd

Browse files
committed
Merge branch 'release/0.1'
2 parents bfa9c56 + cc022eb commit 21c3acd

File tree

12 files changed

+209
-159
lines changed

12 files changed

+209
-159
lines changed

examples/bmark.py

+7-6
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,13 @@
33
# The test matrix may be obtained from http://math.nist.gov/MatrixMarket
44

55
import numpy as np
6+
from pykrylov.linop import PysparseLinearOperator
67
from pykrylov.cgs import CGS
78
from pykrylov.tfqmr import TFQMR
89
from pykrylov.bicgstab import BiCGSTAB
910
from pysparse import spmatrix
1011
from pysparse.sparse.pysparseMatrix import PysparseMatrix as sp
11-
from math import sqrt
12+
import sys
1213

1314
class DiagonalPrec:
1415

@@ -30,9 +31,9 @@ def __call__(self, y, **kwargs):
3031
print hdr
3132
print '-' * len(hdr)
3233

33-
#AA = spmatrix.ll_mat_from_mtx('mcca.mtx')
34-
AA = spmatrix.ll_mat_from_mtx('jpwh_991.mtx')
34+
AA = spmatrix.ll_mat_from_mtx(sys.argv[1])
3535
A = sp(matrix=AA)
36+
op = PysparseLinearOperator(A)
3637

3738
# Create diagonal preconditioner
3839
dp = DiagonalPrec(A)
@@ -42,13 +43,13 @@ def __call__(self, y, **kwargs):
4243
rhs = A*e
4344

4445
for KSolver in [CGS, TFQMR, BiCGSTAB]:
45-
ks = KSolver( lambda v: A*v,
46+
ks = KSolver( op,
4647
#precon = dp,
4748
#verbose=False,
4849
reltol = 1.0e-8
4950
)
50-
ks.solve(rhs, guess = 1+np.arange(n, dtype=np.float), matvec_max=2*n)
51+
ks.solve(rhs, guess = 1+np.arange(n, dtype=op.dtype), matvec_max=2*n)
5152

52-
err = np.linalg.norm(ks.bestSolution-e)/sqrt(n)
53+
err = np.linalg.norm(ks.bestSolution-e)/np.sqrt(n)
5354
print fmt % (ks.acronym, ks.nMatvec, ks.residNorm0, ks.residNorm, err)
5455

pykrylov/bicgstab/bicgstab.py

+17-16
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
__docformat__ = 'restructuredtext'
33

44
import numpy as np
5-
from math import sqrt
5+
66

77
from pykrylov.generic import KrylovMethod
88

@@ -14,9 +14,9 @@ class BiCGSTAB( KrylovMethod ):
1414
1515
A x = b
1616
17-
where the matrix A is unsymmetric and nonsingular.
17+
where the operator A is unsymmetric and nonsingular.
1818
19-
Bi-CGSTAB requires 2 matrix-vector products, 6 dot products and 6 daxpys
19+
Bi-CGSTAB requires 2 operator-vector products, 6 dot products and 6 daxpys
2020
per iteration.
2121
2222
In addition, if a preconditioner is supplied, it needs to solve 2
@@ -33,8 +33,8 @@ class BiCGSTAB( KrylovMethod ):
3333
Computing **13** (2), pp. 631--644, 1992.
3434
"""
3535

36-
def __init__(self, matvec, **kwargs):
37-
KrylovMethod.__init__(self, matvec, **kwargs)
36+
def __init__(self, op, **kwargs):
37+
KrylovMethod.__init__(self, op, **kwargs)
3838

3939
self.name = 'Bi-Conjugate Gradient Stabilized'
4040
self.acronym = 'Bi-CGSTAB'
@@ -53,19 +53,20 @@ def solve(self, rhs, **kwargs):
5353
nMatvec = 0
5454

5555
# Initial guess is zero unless one is supplied
56+
result_type = np.result_type(self.op.dtype, rhs.dtype)
5657
guess_supplied = 'guess' in kwargs.keys()
57-
x = kwargs.get('guess', np.zeros(n))
58+
x = kwargs.get('guess', np.zeros(n)).astype(result_type)
5859
matvec_max = kwargs.get('matvec_max', 2*n)
5960

6061
# Initial residual is the fixed vector
6162
r0 = rhs
6263
if guess_supplied:
63-
r0 = rhs - self.matvec(x)
64+
r0 = rhs - self.op * x
6465
nMatvec += 1
6566

6667
rho = alpha = omega = 1.0
6768
rho_next = np.dot(r0,r0)
68-
residNorm = self.residNorm0 = sqrt(rho_next)
69+
residNorm = self.residNorm0 = np.abs(np.sqrt(rho_next))
6970
threshold = max( self.abstol, self.reltol * self.residNorm0 )
7071

7172
finished = (residNorm <= threshold or nMatvec >= matvec_max)
@@ -78,8 +79,8 @@ def solve(self, rhs, **kwargs):
7879

7980
if not finished:
8081
r = r0.copy()
81-
p = np.zeros(n)
82-
v = np.zeros(n)
82+
p = np.zeros(n, dtype=result_type)
83+
v = np.zeros(n, dtype=result_type)
8384

8485
while not finished:
8586

@@ -93,17 +94,17 @@ def solve(self, rhs, **kwargs):
9394

9495
# Compute preconditioned search direction
9596
if self.precon is not None:
96-
q = self.precon(p)
97+
q = self.precon * p
9798
else:
9899
q = p
99100

100-
v = self.matvec(q) ; nMatvec += 1
101+
v = self.op * q ; nMatvec += 1
101102

102103
alpha = rho/np.dot(r0, v)
103104
s = r - alpha * v
104105

105106
# Check for CGS termination
106-
residNorm = sqrt(np.dot(s,s))
107+
residNorm = np.linalg.norm(s)
107108

108109
self.logger.info('%6d %8.2e' % (nMatvec, residNorm))
109110

@@ -117,11 +118,11 @@ def solve(self, rhs, **kwargs):
117118
continue
118119

119120
if self.precon is not None:
120-
z = self.precon(s)
121+
z = self.precon * s
121122
else:
122123
z = s
123124

124-
t = self.matvec(z) ; nMatvec += 1
125+
t = self.op * z ; nMatvec += 1
125126
omega = np.dot(t,s)/np.dot(t,t)
126127
rho_next = -omega * np.dot(r0,t)
127128

@@ -135,7 +136,7 @@ def solve(self, rhs, **kwargs):
135136
x += z
136137
x += alpha * q
137138

138-
residNorm = sqrt(np.dot(r,r))
139+
residNorm = np.linalg.norm(r)
139140

140141
self.logger.info('%6d %8.2e' % (nMatvec, residNorm))
141142

pykrylov/cg/cg.py

+20-20
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
__docformat__ = 'restructuredtext'
33

44
import numpy as np
5-
from math import sqrt
65

76
from pykrylov.tools.utils import check_symmetric
87
from pykrylov.generic import KrylovMethod
@@ -15,24 +14,24 @@ class CG( KrylovMethod ):
1514
1615
A x = b
1716
18-
where the matrix A is square, symmetric and positive definite. This is
17+
where the operator A is square, symmetric and positive definite. This is
1918
equivalent to solving the unconstrained convex quadratic optimization
2019
problem
2120
2221
minimize -<b,x> + 1/2 <x, Ax>
2322
2423
in the variable x.
2524
26-
CG performs 1 matrix-vector product, 2 dot products and 3 daxpys per
25+
CG performs 1 operator-vector product, 2 dot products and 3 daxpys per
2726
iteration.
2827
2928
If a preconditioner is supplied, it needs to solve one preconditioning
3029
system per iteration. Our implementation is standard and follows [Kelley]_
3130
and [Templates]_.
3231
"""
3332

34-
def __init__(self, matvec, **kwargs):
35-
KrylovMethod.__init__(self, matvec, **kwargs)
33+
def __init__(self, op, **kwargs):
34+
KrylovMethod.__init__(self, op, **kwargs)
3635

3736
self.name = 'Conjugate Gradient'
3837
self.acronym = 'CG'
@@ -52,9 +51,9 @@ def solve(self, rhs, **kwargs):
5251
:Keywords:
5352
5453
:guess: Initial guess (Numpy array). Default: 0.
55-
:matvec_max: Max. number of matrix-vector produts. Default: 2n.
56-
:check_symmetric: Ensure matrix is symmetric. Default: False.
57-
:check_curvature: Ensure matrix is positive definite. Default: True.
54+
:matvec_max: Max. number of operator-vector produts. Default: 2n.
55+
:check_symmetric: Ensure operator is symmetric. Default: False.
56+
:check_curvature: Ensure operator is positive definite. Default: True.
5857
:store_resids: Store full residual vector history. Default: False.
5958
:store_iterates: Store full iterate history. Default: False.
6059
@@ -68,13 +67,14 @@ def solve(self, rhs, **kwargs):
6867
store_iterates = kwargs.get('store_iterates', False)
6968

7069
if check_sym:
71-
if not check_symmetric(self.matvec):
72-
self.logger.error('Coefficient matrix is not symmetric')
70+
if not check_symmetric(self.op):
71+
self.logger.error('Coefficient operator is not symmetric')
7372
return
7473

7574
# Initial guess
75+
result_type = np.result_type(self.op.dtype, rhs.dtype)
7676
guess_supplied = 'guess' in kwargs.keys()
77-
x = kwargs.get('guess', np.zeros(n))
77+
x = kwargs.get('guess', np.zeros(n)).astype(result_type)
7878

7979
if store_iterates:
8080
self.iterates.append(x.copy())
@@ -84,20 +84,20 @@ def solve(self, rhs, **kwargs):
8484
# Initial residual vector
8585
r = -rhs
8686
if guess_supplied:
87-
r += self.matvec(x)
87+
r += self.op * x
8888
nMatvec += 1
8989

9090
# Initial preconditioned residual vector
9191
if self.precon is not None:
92-
y = self.precon(r)
92+
y = self.precon * r
9393
else:
9494
y = r
9595

9696
if store_resids:
9797
self.resids.append(y.copy())
9898

9999
ry = np.dot(r,y)
100-
self.residNorm0 = residNorm = sqrt(ry)
100+
self.residNorm0 = residNorm = np.abs(np.sqrt(ry))
101101
self.residHistory.append(self.residNorm0)
102102
threshold = max(self.abstol, self.reltol * self.residNorm0)
103103

@@ -112,13 +112,13 @@ def solve(self, rhs, **kwargs):
112112

113113
while residNorm > threshold and nMatvec < matvec_max and definite:
114114

115-
Ap = self.matvec(p)
115+
Ap = self.op * p
116116
nMatvec += 1
117117
pAp = np.dot(p, Ap)
118118

119119
if check_curvature:
120-
if pAp <= 0:
121-
self.logger.error('Coefficient matrix is not positive definite')
120+
if np.imag(pAp) > 1.0e-8 * np.abs(pAp) or np.real(pAp) <= 0:
121+
self.logger.error('Coefficient operator is not positive definite')
122122
self.infiniteDescent = p
123123
definite = False
124124
continue
@@ -135,7 +135,7 @@ def solve(self, rhs, **kwargs):
135135

136136
# Compute preconditioned residual
137137
if self.precon is not None:
138-
y = self.precon(r)
138+
y = self.precon * r
139139
else:
140140
y = r
141141

@@ -151,10 +151,10 @@ def solve(self, rhs, **kwargs):
151151
p -= r
152152

153153
ry = ry_next
154-
residNorm = sqrt(ry)
154+
residNorm = np.abs(np.sqrt(ry))
155155
self.residHistory.append(residNorm)
156156

157-
info = '%6d %7.1e %8.1e' % (nMatvec, residNorm, pAp)
157+
info = '%6d %7.1e %8.1e' % (nMatvec, residNorm, np.real(pAp))
158158
self.logger.info(info)
159159

160160

pykrylov/cgs/cgs.py

+14-14
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
__docformat__ = 'restructuredtext'
33

44
import numpy as np
5-
from math import sqrt
65

76
from pykrylov.generic import KrylovMethod
87

@@ -14,10 +13,10 @@ class CGS( KrylovMethod ):
1413
1514
A x = b
1615
17-
where the matrix A may be unsymmetric.
16+
where the operator A may be unsymmetric.
1817
19-
CGS requires 2 matrix-vector products with A, 3 dot products and 7 daxpys
20-
per iteration. It does not require products with the transpose of A.
18+
CGS requires 2 operator-vector products with A, 3 dot products and 7 daxpys
19+
per iteration. It does not require products with the adjoint of A.
2120
2221
If a preconditioner is supplied, CGS needs to solve two preconditioning
2322
systems per iteration. The original description appears in [Sonn89]_, which
@@ -31,8 +30,8 @@ class CGS( KrylovMethod ):
3130
Computing **10** (1), pp. 36--52, 1989.
3231
"""
3332

34-
def __init__(self, matvec, **kwargs):
35-
KrylovMethod.__init__(self, matvec, **kwargs)
33+
def __init__(self, op, **kwargs):
34+
KrylovMethod.__init__(self, op, **kwargs)
3635

3736
self.name = 'Conjugate Gradient Squared'
3837
self.acronym = 'CGS'
@@ -51,16 +50,17 @@ def solve(self, rhs, **kwargs):
5150
nMatvec = 0
5251

5352
# Initial guess is zero unless one is supplied
53+
result_type = np.result_type(self.op.dtype, rhs.dtype)
5454
guess_supplied = 'guess' in kwargs.keys()
55-
x = kwargs.get('guess', np.zeros(n))
55+
x = kwargs.get('guess', np.zeros(n)).astype(result_type)
5656
matvec_max = kwargs.get('matvec_max', 2*n)
5757

5858
r0 = rhs # Fixed vector throughout
5959
if guess_supplied:
60-
r0 = rhs - self.matvec(x)
60+
r0 = rhs - self.op * x
6161

6262
rho = np.dot(r0,r0)
63-
residNorm = sqrt(rho)
63+
residNorm = np.abs(np.sqrt(rho))
6464
self.residNorm0 = residNorm
6565
threshold = max( self.abstol, self.reltol * self.residNorm0 )
6666
self.logger.info('Initial residual = %8.2e\n' % self.residNorm0)
@@ -76,27 +76,27 @@ def solve(self, rhs, **kwargs):
7676
while not finished:
7777

7878
if self.precon is not None:
79-
y = self.precon(p)
79+
y = self.precon * p
8080
else:
8181
y = p
8282

83-
v = self.matvec(y) ; nMatvec += 1
83+
v = self.op * y ; nMatvec += 1
8484
sigma = np.dot(r0,v)
8585
alpha = rho/sigma
8686
q = u - alpha * v
8787

8888
if self.precon is not None:
89-
z = self.precon(u+q)
89+
z = self.precon * (u+q)
9090
else:
9191
z = u+q
9292

9393
# Update solution and residual
9494
x += alpha * z
95-
Az = self.matvec(z) ; nMatvec += 1
95+
Az = self.op * z ; nMatvec += 1
9696
r -= alpha * Az
9797

9898
# Update residual norm and check convergence
99-
residNorm = sqrt(np.dot(r,r))
99+
residNorm = np.linalg.norm(r)
100100

101101
if residNorm <= threshold or nMatvec >= matvec_max:
102102
finished = True

0 commit comments

Comments
 (0)