Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update312 #403

Merged
merged 9 commits into from
Mar 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,7 @@ jobs:
run: |
pytest --cov=./ --cov-report=xml .

- name: Upload coverage
uses: codecov/codecov-action@v3
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v4-beta
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
4 changes: 4 additions & 0 deletions codecov.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
coverage:
status:
project: off
patch: off
2 changes: 1 addition & 1 deletion pyamg/aggregation/adaptive.py
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ def adaptive_sa_solver(A, initial_candidates=None, symmetry='hermitian',
try:
A = csr_matrix(A)
warn('Implicit conversion of A to CSR', SparseEfficiencyWarning)
except BaseException as e:
except Exception as e:
raise TypeError('Argument A must have type csr_matrix or '
'bsr_matrix, or be convertible to csr_matrix') from e

Expand Down
2 changes: 1 addition & 1 deletion pyamg/aggregation/aggregate.py
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ def pairwise_aggregation(A, matchings=2, theta=0.25,
try:
A = A.tocsr()
warn('Implicit conversion of A to csr', sparse.SparseEfficiencyWarning)
except BaseException as e:
except Exception as e:
raise TypeError('Invalid matrix type, must be CSR or BSR.') from e

index_type = A.indptr.dtype
Expand Down
2 changes: 1 addition & 1 deletion pyamg/aggregation/aggregation.py
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ def smoothed_aggregation_solver(A, B=None, BH=None,
try:
A = csr_matrix(A)
warn('Implicit conversion of A to CSR', SparseEfficiencyWarning)
except BaseException as e:
except Exception as e:
raise TypeError('Argument A must have type csr_matrix or bsr_matrix, '
'or be convertible to csr_matrix') from e

Expand Down
2 changes: 1 addition & 1 deletion pyamg/aggregation/pairwise.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ def pairwise_solver(A,
try:
A = csr_matrix(A)
warn('Implicit conversion of A to CSR', SparseEfficiencyWarning)
except BaseException as e:
except Exception as e:
raise TypeError('Argument A must have type csr_matrix or bsr_matrix, '
'or be convertible to csr_matrix') from e

Expand Down
2 changes: 1 addition & 1 deletion pyamg/aggregation/rootnode.py
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ def rootnode_solver(A, B=None, BH=None,
A = csr_matrix(A)
warn('Implicit conversion of A to CSR',
SparseEfficiencyWarning)
except BaseException as e:
except Exception as e:
raise TypeError('Argument A must have type csr_matrix, '
'bsr_matrix, or be convertible to csr_matrix') from e

Expand Down
20 changes: 5 additions & 15 deletions pyamg/aggregation/tests/test_aggregation.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
from numpy.testing import TestCase, assert_approx_equal, \
assert_array_almost_equal
from scipy import sparse
import scipy.linalg as sla
from scipy.sparse import SparseEfficiencyWarning

from pyamg.util.utils import diag_sparse
Expand All @@ -31,11 +30,9 @@ def run_cases(self, opts):
b = A * np.random.rand(A.shape[0])

residuals = []
x_sol = ml.solve(b, x0=x, maxiter=30, tol=1e-10,
residuals=residuals)
x_sol = ml.solve(b, x0=x, maxiter=30, tol=1e-10, residuals=residuals)
del x_sol
convergence_ratio =\
(residuals[-1] / residuals[0]) ** (1.0 / len(residuals))
convergence_ratio = (residuals[-1] / residuals[0])**(1.0 / len(residuals))
assert convergence_ratio < 0.9

def test_strength_of_connection(self):
Expand Down Expand Up @@ -110,11 +107,9 @@ def run_cases(self, opts):
b = A * np.random.rand(A.shape[0])
residuals = []

x_sol = ml.solve(b, x0=x, maxiter=30, tol=1e-10,
residuals=residuals)
x_sol = ml.solve(b, x0=x, maxiter=30, tol=1e-10, residuals=residuals)
del x_sol
convergence_ratio =\
(residuals[-1] / residuals[0]) ** (1.0 / len(residuals))
convergence_ratio = (residuals[-1] / residuals[0])**(1.0 / len(residuals))
assert convergence_ratio < 0.9

def test_strength_of_connection(self):
Expand Down Expand Up @@ -400,12 +395,7 @@ def test_coarse_solver_opts(self):
'gauss_seidel'))
coarse_solver_pairs.append(('gauss_seidel', 'jacobi'))
coarse_solver_pairs.append(('cg', ('cg', {'tol': 10.0})))
# scipy >= 1.7: pinv takes 'rtol'
# scipy < 1.7: pinv takes 'cond'
kword = 'rtol'
if kword not in sla.pinv.__code__.co_varnames:
kword = 'cond'
coarse_solver_pairs.append(('pinv', ('pinv', {kword: 1.0})))
coarse_solver_pairs.append(('pinv', ('pinv', {'rtol': 1.0})))

for coarse1, coarse2 in coarse_solver_pairs:
r1 = []
Expand Down
8 changes: 1 addition & 7 deletions pyamg/aggregation/tests/test_rootnode.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
import warnings
import numpy as np
from scipy import sparse
import scipy.linalg as sla
from scipy.sparse import SparseEfficiencyWarning

from numpy.testing import TestCase, assert_approx_equal, \
Expand Down Expand Up @@ -388,12 +387,7 @@ def test_coarse_solver_opts(self):
{'iterations': 30}), 'gauss_seidel'))
coarse_solver_pairs.append(('gauss_seidel', 'jacobi'))
coarse_solver_pairs.append(('cg', ('cg', {'tol': 10.0})))
# scipy >= 1.7: pinv takes 'rtol'
# scipy < 1.7: pinv takes 'cond'
kword = 'rtol'
if kword not in sla.pinv.__code__.co_varnames:
kword = 'cond'
coarse_solver_pairs.append(('pinv', ('pinv', {kword: 1.0})))
coarse_solver_pairs.append(('pinv', ('pinv', {'rtol': 1.0})))

for coarse1, coarse2 in coarse_solver_pairs:
r1 = []
Expand Down
4 changes: 2 additions & 2 deletions pyamg/blackbox.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ def make_csr(A):
try:
A = csr_matrix(A)
print('Implicit conversion of A to CSR in pyamg.blackbox.make_csr')
except BaseException as e:
except Exception as e:
raise TypeError('Argument A must have type csr_matrix or '
'bsr_matrix, or be convertible to csr_matrix') from e

Expand Down Expand Up @@ -201,7 +201,7 @@ def solver(A, config):
presmoother=config['presmoother'],
postsmoother=config['postsmoother'],
keep=config['keep'])
except BaseException as e:
except Exception as e:
raise TypeError('Failed generating smoothed_aggregation_solver') from e


Expand Down
2 changes: 1 addition & 1 deletion pyamg/classical/classical.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ def ruge_stuben_solver(A,
A = csr_matrix(A)
warn('Implicit conversion of A to CSR',
SparseEfficiencyWarning)
except BaseException as e:
except Exception as e:
raise TypeError('Argument A must have type csr_matrix, '
'or be convertible to csr_matrix') from e
# preprocess A
Expand Down
6 changes: 3 additions & 3 deletions pyamg/classical/interpolate.py
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ def injection_interpolation(A, splitting):
warn('Implicit conversion of A to csr', SparseEfficiencyWarning)
n = A.shape[0]
blocksize = 1
except BaseException as e:
except Exception as e:
raise TypeError('Invalid matrix type, must be CSR or BSR.') from e

P_rowptr = np.append(np.array([0], dtype=A.indptr.dtype),
Expand Down Expand Up @@ -286,7 +286,7 @@ def one_point_interpolation(A, C, splitting, by_val=False):
warn('Implicit conversion of A to csr', SparseEfficiencyWarning)
n = A.shape[0]
blocksize = 1
except BaseException as e:
except Exception as e:
raise TypeError('Invalid matrix type, must be CSR or BSR.') from e

nc = np.sum(splitting)
Expand Down Expand Up @@ -376,7 +376,7 @@ def local_air(A, splitting, theta=0.1, norm='abs', degree=1,
warn('Implicit conversion of A to csr', SparseEfficiencyWarning)
C = classical_strength_of_connection(A=A, theta=theta, block=False, norm=norm)
blocksize = 1
except BaseException as e:
except Exception as e:
raise TypeError('Invalid matrix type, must be CSR or BSR.') from e

Cpts = np.array(np.where(splitting == 1)[0], dtype=A.indptr.dtype)
Expand Down
17 changes: 11 additions & 6 deletions pyamg/krylov/tests/test_scipy.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Test scipy methods."""
import inspect
from functools import partial

import numpy as np
Expand Down Expand Up @@ -37,20 +38,24 @@ def cb(x, normb):
x0 = case['x0']
tol = case['tol']

kwargs = dict(tol=tol, restart=3, maxiter=2)

mgsres = []
_ = gmres_mgs(A, b, x0, residuals=mgsres,
tol=tol, restart=3, maxiter=2)
_ = gmres_mgs(A, b, x0, residuals=mgsres, **kwargs)

hhres = []
_ = gmres_householder(A, b, x0, residuals=hhres,
tol=tol, restart=3, maxiter=2)
_ = gmres_householder(A, b, x0, residuals=hhres, **kwargs)

scipyres = []
normb = np.linalg.norm(b)
callback = partial(cb, normb=normb)

_ = sla.gmres(A, b, x0, callback=callback, callback_type='pr_norm',
tol=tol, atol=0, restart=3, maxiter=2)
# check if scipy gmres has rtol
kwargs['atol'] = 0
if 'rtol' in inspect.getfullargspec(sla.gmres).args:
kwargs['rtol'] = kwargs.pop(tol)

_ = sla.gmres(A, b, x0, callback=callback, callback_type='pr_norm', **kwargs)

assert_array_almost_equal(mgsres[1:], scipyres)
assert_array_almost_equal(hhres[1:], scipyres)
10 changes: 8 additions & 2 deletions pyamg/multilevel.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Generic AMG solver."""
import inspect

from warnings import warn

Expand Down Expand Up @@ -457,7 +458,6 @@ def solve(self, b, x0=None, tol=1e-5, maxiter=100, cycle='V', accel=None,
accel = getattr(krylov, accel)
else:
accel = getattr(sla, accel)
kwargs['atol'] = 'legacy'

M = self.aspreconditioner(cycle=cycle)

Expand Down Expand Up @@ -485,7 +485,13 @@ def callback_wrapper(x):
else:
callback_wrapper = callback

x, info = accel(A, b, x0=x0, tol=tol, maxiter=maxiter, M=M,
# for scipy solvers, see if rtol is available
kwargs['tol'] = tol
kwargs['atol'] = 0
if 'rtol' in inspect.getfullargspec(accel).args:
kwargs['rtol'] = kwargs.pop(tol)

x, info = accel(A, b, x0=x0, maxiter=maxiter, M=M,
callback=callback_wrapper, **kwargs)
if return_info:
return x, info
Expand Down
20 changes: 9 additions & 11 deletions pyamg/tests/test_multilevel.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
"""Test MultilevelSolver class."""
import inspect

import numpy as np
from numpy.testing import TestCase, assert_almost_equal, assert_equal
from scipy import sparse
Expand Down Expand Up @@ -53,9 +55,13 @@ def test_aspreconditioner(self):

ml = smoothed_aggregation_solver(A)

kwargs = dict(tol=1e-8, maxiter=30, atol=0)
if 'rtol' in inspect.getfullargspec(cg).args:
kwargs['rtol'] = kwargs.pop('tol')

for cycle in ['V', 'W', 'F']:
M = ml.aspreconditioner(cycle=cycle)
x, info = cg(A, b, tol=1e-8, maxiter=30, M=M, atol='legacy')
x, info = cg(A, b, M=M, **kwargs)
# cg satisfies convergence in the preconditioner norm
assert precon_norm(b - A*x, ml) < 1e-8*precon_norm(b, ml)

Expand All @@ -78,24 +84,16 @@ def test_accel(self):

# cg halts based on the preconditioner norm
for accel in ['cg', cg]:
x = ml.solve(b, maxiter=30, tol=1e-8, accel=accel)
assert precon_norm(b - A*x, ml) < 1e-8*precon_norm(b, ml)
residuals = []
x = ml.solve(b, maxiter=30, tol=1e-8, residuals=residuals,
accel=accel)
x = ml.solve(b, maxiter=30, tol=1e-8, residuals=residuals, accel=accel)
assert precon_norm(b - A*x, ml) < 1e-8*precon_norm(b, ml)
# print residuals
assert_almost_equal(precon_norm(b - A*x, ml), residuals[-1])

# cgs and bicgstab use the Euclidean norm
for accel in ['bicgstab', 'cgs', bicgstab]:
x = ml.solve(b, maxiter=30, tol=1e-8, accel=accel)
assert np.linalg.norm(b - A*x) < 1e-8*np.linalg.norm(b)
residuals = []
x = ml.solve(b, maxiter=30, tol=1e-8, residuals=residuals,
accel=accel)
x = ml.solve(b, maxiter=30, tol=1e-8, residuals=residuals, accel=accel)
assert np.linalg.norm(b - A*x) < 1e-8*np.linalg.norm(b)
# print residuals
assert_almost_equal(np.linalg.norm(b - A*x), residuals[-1])

def test_cycle_complexity(self):
Expand Down
18 changes: 14 additions & 4 deletions pyamg/util/tests/test_utils.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
"""Test utils."""
import inspect

import numpy as np
from scipy.sparse import (csr_matrix, csc_matrix, isspmatrix,
bsr_matrix, isspmatrix_bsr,
Expand Down Expand Up @@ -167,8 +169,12 @@ def test_profile_solver(self):

opts = []
opts.append({})
opts.append({'accel': cg, 'atol': 'legacy'})
opts.append({'accel': cg, 'tol': 1e-10, 'atol': 'legacy'})

# does cg have rtol?
nextopt = dict(accel=cg, tol=1e-10, atol=0)
if 'rtol' in inspect.getfullargspec(cg).args:
nextopt['rtol'] = nextopt.pop('tol')
opts.append(nextopt)

for kwargs in opts:
residuals = profile_solver(ml, **kwargs)
Expand Down Expand Up @@ -1194,8 +1200,12 @@ def test_profile_solver(self):

opts = []
opts.append({})
opts.append({'accel': cg, 'atol': 'legacy'})
opts.append({'accel': cg, 'tol': 1e-10, 'atol': 'legacy'})

# does cg have rtol?
nextopt = dict(accel=cg, tol=1e-10, atol=0)
if 'rtol' in inspect.getfullargspec(cg).args:
nextopt['rtol'] = nextopt.pop('tol')
opts.append(nextopt)

for kwargs in opts:
residuals = profile_solver(ml, **kwargs)
Expand Down
2 changes: 1 addition & 1 deletion pyamg/vis/vis_coarse.py
Original file line number Diff line number Diff line change
Expand Up @@ -279,4 +279,4 @@ def check_input(V=None, E2V=None, AggOp=None, A=None, splitting=None, mesh_type=
if mesh_type is not None:
valid_mesh_types = ('vertex', 'tri', 'quad', 'tet', 'hex')
if mesh_type not in valid_mesh_types:
raise ValueError(f'mesh_type should be {" or ".join(valid_mesh_types)}')
raise ValueError(f'mesh_type should one of {valid_mesh_types}')
2 changes: 1 addition & 1 deletion requirements-dev.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
numpy
scipy>=1.7.0
scipy>=1.8.0
pytest
pep8-naming
flake8-quotes
Expand Down
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
numpy
scipy>=1.7.0
scipy>=1.8.0
4 changes: 2 additions & 2 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ packages = find:
platforms = any
python_requires = >=3.8
install_requires =
numpy>=1.7.0
scipy>=1.7.0
numpy
scipy>=1.8.0
tests_require =
pytest>=2

Expand Down
Loading