Skip to content

Commit f01157c

Browse files
Anushka SinghAnushka Singh
authored andcommitted
Fix missing .solve method in CG and BiCG when used via transpose()
Previously, CG and BiCG defined the `.solve` method dynamically inside `.dot()`, based on whether a preconditioner was provided. This caused errors when `.solve()` was called on transposed solver objects, since `.dot()` had not been invoked yet and `.solve` was not initialized. This commit moves the `.solve` assignment logic into the constructor (`__init__`), ensuring `.solve` is always available and correctly bound, even for transposed instances. This makes CG/BiCG consistent with other solver classes where `.solve()` is always defined.
1 parent 62ab79f commit f01157c

2 files changed

Lines changed: 25 additions & 6 deletions

File tree

psydac/linalg/solvers.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,12 @@ def __init__(self, A, *, pc=None, x0=None, tol=1e-6, maxiter=1000, verbose=False
138138

139139
self._info = None
140140

141+
if pc is None:
142+
self.solve = self.solve_without_pc
143+
else:
144+
self.solve = self.solve_with_pc
145+
146+
141147
def solve_without_pc(self, b, out=None):
142148
"""
143149
Conjugate gradient algorithm for solving linear system Ax=b.
@@ -604,6 +610,11 @@ def __init__(self, A, *, pc=None, x0=None, tol=1e-6, maxiter=1000, verbose=False
604610
"rp0")}
605611
self._info = None
606612

613+
if pc is None:
614+
self.solve = self.solve_without_pc
615+
else:
616+
self.solve = self.solve_with_pc
617+
607618
def solve_without_pc(self, b, out=None):
608619
"""
609620
Biconjugate gradient stabilized method (BCGSTAB) algorithm for solving linear system Ax=b.

psydac/linalg/tests/test_solvers.py

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -73,9 +73,14 @@ def test_solver_tridiagonal(n, p, dtype, solver, verbose=False):
7373
else:
7474
diagonals = [1,6,3]
7575

76-
if solver == 'bicgstab' and pc != None and dtype == complex:
77-
# pbicgstab only works for real matrices
78-
return
76+
if solver == 'bicgstab' and dtype == complex:
77+
try:
78+
if pc is not None:
79+
# pbicgstab only works for real matrices
80+
return
81+
except NameError:
82+
pass
83+
7984
elif solver == 'gmres':
8085
if dtype==complex:
8186
diagonals = [-7-2j,-6-2j,-1-10j]
@@ -134,6 +139,9 @@ def test_solver_tridiagonal(n, p, dtype, solver, verbose=False):
134139
assert np.array_equal(x2.toarray(), solv_x0.toarray())
135140
assert x2 is not solv_x0
136141

142+
# So when you get a new solver object (via .transpose()), you must either:
143+
# 1.Initialize solve properly (call some init routine or assign it), or
144+
# 2. Make solve a property that dynamically returns the correct method
137145
xt = solvt.solve(bet)
138146
solvt_x0 = solvt._options["x0"]
139147
assert np.array_equal(xt.toarray(), solvt_x0.toarray())
@@ -144,7 +152,7 @@ def test_solver_tridiagonal(n, p, dtype, solver, verbose=False):
144152
assert np.array_equal(xh.toarray(), solvh_x0.toarray())
145153
assert xh is not solvh_x0
146154

147-
if (solver != 'cg' or (solver == 'cg' and 'pc' in locals() and pc == None)):
155+
if (solver != 'cg' or (solver == 'cg' and ('pc' == None or pc not in locals()) )):
148156
# PCG only works with operators with diagonal
149157
xc = solv2 @ be2
150158
solv2_x0 = solv2._options["x0"]
@@ -157,7 +165,7 @@ def test_solver_tridiagonal(n, p, dtype, solver, verbose=False):
157165
b2 = A @ x2
158166
bt = A.T @ xt
159167
bh = A.H @ xh
160-
if (solver != 'cg' or (solver == 'cg' and 'pc' in locals() and pc == None)):
168+
if (solver != 'cg' or (solver == 'cg' and ('pc' == None or pc not in locals()) )):
161169
bc = A @ A @ xc
162170

163171
err = b - be
@@ -169,7 +177,7 @@ def test_solver_tridiagonal(n, p, dtype, solver, verbose=False):
169177
errh = bh - beh
170178
errh_norm = np.linalg.norm( errh.toarray() )
171179

172-
if (solver != 'cg' or (solver == 'cg' and 'pc' in locals() and pc == None)):
180+
if (solver != 'cg' or (solver == 'cg' and ('pc' == None or pc not in locals()) )):
173181
errc = bc - be2
174182
errc_norm = np.linalg.norm( errc.toarray() )
175183

0 commit comments

Comments
 (0)