def test_matrix_op_call(matrix): """Validate result from calls to matrix operators against Numpy.""" dense_matrix = matrix sparse_matrix = scipy.sparse.coo_matrix(dense_matrix) # Default 1d case dmat_op = MatrixOperator(dense_matrix) smat_op = MatrixOperator(sparse_matrix) xarr, x = noise_elements(dmat_op.domain) true_result = dense_matrix.dot(xarr) assert all_almost_equal(dmat_op(x), true_result) assert all_almost_equal(smat_op(x), true_result) out = dmat_op.range.element() dmat_op(x, out=out) assert all_almost_equal(out, true_result) smat_op(x, out=out) assert all_almost_equal(out, true_result) # Multi-dimensional case domain = odl.rn((2, 2, 4)) mat_op = MatrixOperator(dense_matrix, domain, axis=2) xarr, x = noise_elements(mat_op.domain) true_result = np.moveaxis(np.tensordot(dense_matrix, xarr, (1, 2)), 0, 2) assert all_almost_equal(mat_op(x), true_result) out = mat_op.range.element() mat_op(x, out=out) assert all_almost_equal(out, true_result)
def test_mat_op_adjoint(fn): # Square cases sparse_mat = _sparse_matrix(fn) dense_mat = _dense_matrix(fn) op_sparse = MatrixOperator(sparse_mat, fn, fn) op_dense = MatrixOperator(dense_mat, fn, fn) # Just test if it runs, nothing interesting to test here op_sparse.adjoint op_dense.adjoint # Rectangular case rect_mat = 2 * np.eye(2, 3) r2, r3 = odl.rn(2), odl.rn(3) c2 = odl.cn(2) op = MatrixOperator(rect_mat, r3, r2) op_adj = op.adjoint assert op_adj.domain == op.range assert op_adj.range == op.domain assert np.array_equal(op_adj.matrix, op.matrix.conj().T) assert np.array_equal(op_adj.adjoint.matrix, op.matrix) # The operator Rn -> Cn has no adjoint op_noadj = MatrixOperator(rect_mat, r3, c2) with pytest.raises(NotImplementedError): op_noadj.adjoint
def test_matrix_op_adjoint(matrix): """Test if the adjoint of matrix operators is correct.""" dense_matrix = matrix sparse_matrix = scipy.sparse.coo_matrix(dense_matrix) tol = 2 * matrix.size * np.finfo(matrix.dtype).resolution # Default 1d case dmat_op = MatrixOperator(dense_matrix) smat_op = MatrixOperator(sparse_matrix) x = noise_element(dmat_op.domain) y = noise_element(dmat_op.range) inner_ran = dmat_op(x).inner(y) inner_dom = x.inner(dmat_op.adjoint(y)) assert inner_ran == pytest.approx(inner_dom, rel=tol, abs=tol) inner_ran = smat_op(x).inner(y) inner_dom = x.inner(smat_op.adjoint(y)) assert inner_ran == pytest.approx(inner_dom, rel=tol, abs=tol) # Multi-dimensional case domain = odl.tensor_space((2, 2, 4), matrix.dtype) mat_op = MatrixOperator(dense_matrix, domain, axis=2) x = noise_element(mat_op.domain) y = noise_element(mat_op.range) inner_ran = mat_op(x).inner(y) inner_dom = x.inner(mat_op.adjoint(y)) assert inner_ran == pytest.approx(inner_dom, rel=tol, abs=tol)
def test_mat_op_call(fn): # Square cases sparse_mat = _sparse_matrix(fn) dense_mat = _dense_matrix(fn) xarr, x = noise_elements(fn) op_sparse = MatrixOperator(sparse_mat, fn, fn) op_dense = MatrixOperator(dense_mat, fn, fn) yarr_sparse = sparse_mat.dot(xarr) yarr_dense = dense_mat.dot(xarr) # Out-of-place y = op_sparse(x) assert all_almost_equal(y, yarr_sparse) y = op_dense(x) assert all_almost_equal(y, yarr_dense) # In-place y = fn.element() op_sparse(x, out=y) assert all_almost_equal(y, yarr_sparse) y = fn.element() op_dense(x, out=y) assert all_almost_equal(y, yarr_dense) # Rectangular case rect_mat = 2 * np.eye(2, 3) r2, r3 = odl.rn(2), odl.rn(3) op = MatrixOperator(rect_mat, r3, r2) xarr = np.arange(3, dtype=float) x = r3.element(xarr) yarr = rect_mat.dot(xarr) # Out-of-place y = op(x) assert all_almost_equal(y, yarr) # In-place y = r2.element() op(x, out=y) assert all_almost_equal(y, yarr)
def test_mat_op_inverse(fn): # Sparse case sparse_mat = _sparse_matrix(fn) op_sparse = MatrixOperator(sparse_mat, fn, fn) op_sparse_inv = op_sparse.inverse assert op_sparse_inv.domain == op_sparse.range assert op_sparse_inv.range == op_sparse.domain assert all_almost_equal(op_sparse_inv.matrix, np.linalg.inv(op_sparse.matrix.todense())) assert all_almost_equal(op_sparse_inv.inverse.matrix, op_sparse.matrix.todense()) # Test application x = noise_element(fn) assert all_almost_equal(x, op_sparse.inverse(op_sparse(x))) # Dense case dense_mat = _dense_matrix(fn) op_dense = MatrixOperator(dense_mat, fn, fn) op_dense_inv = op_dense.inverse assert op_dense_inv.domain == op_dense.range assert op_dense_inv.range == op_dense.domain assert all_almost_equal(op_dense_inv.matrix, np.linalg.inv(op_dense.matrix)) assert all_almost_equal(op_dense_inv.inverse.matrix, op_dense.matrix) # Test application x = noise_element(fn) assert all_almost_equal(x, op_dense.inverse(op_dense(x)))
def test_matrix_op_call_explicit(): """Validate result from call to matrix op against explicit calculation.""" mat = np.ones((3, 2)) xarr = np.array([[[0, 1], [2, 3]], [[4, 5], [6, 7]]], dtype=float) # Multiplication along `axis` with `mat` is the same as summation # along `axis` and stacking 3 times along the same axis for axis in range(3): mat_op = MatrixOperator(mat, domain=odl.rn(xarr.shape), axis=axis) result = mat_op(xarr) true_result = np.repeat(np.sum(xarr, axis=axis, keepdims=True), repeats=3, axis=axis) assert result.shape == true_result.shape assert np.allclose(result, true_result)
def test_matrix_op_inverse(): """Test if the inverse of matrix operators is correct.""" dense_matrix = np.ones((3, 3)) + 4 * np.eye(3) # invertible sparse_matrix = scipy.sparse.coo_matrix(dense_matrix) # Default 1d case dmat_op = MatrixOperator(dense_matrix) smat_op = MatrixOperator(sparse_matrix) x = noise_element(dmat_op.domain) md_x = dmat_op(x) mdinv_md_x = dmat_op.inverse(md_x) assert all_almost_equal(x, mdinv_md_x) ms_x = smat_op(x) msinv_ms_x = smat_op.inverse(ms_x) assert all_almost_equal(x, msinv_ms_x) # Multi-dimensional case domain = odl.tensor_space((2, 2, 3), dense_matrix.dtype) mat_op = MatrixOperator(dense_matrix, domain, axis=2) x = noise_element(mat_op.domain) m_x = mat_op(x) minv_m_x = mat_op.inverse(m_x) assert all_almost_equal(x, minv_m_x)
def test_mat_op_init_and_basic_properties(): """Test initialization and basic properties of MatrixOperator.""" # Test default domain and range r2 = odl.rn(2) op_real = MatrixOperator([[1.0, 2], [-1, 0.5]]) assert op_real.domain == r2 assert op_real.range == r2 c2 = odl.cn(2) op_complex = MatrixOperator([[1.0, 2 + 1j], [-1 - 1j, 0.5]]) assert op_complex.domain == c2 assert op_complex.range == c2 int2 = odl.fn(2, dtype=int) op_int = MatrixOperator([[1, 2], [-1, 0]]) assert op_int.domain == int2 assert op_int.range == int2 # Rectangular rect_mat = 2 * np.eye(2, 3) r3 = odl.rn(3) op = MatrixOperator(rect_mat) assert op.domain == r3 assert op.range == r2 MatrixOperator(rect_mat, domain=r3, range=r2) with pytest.raises(ValueError): MatrixOperator(rect_mat, domain=r2, range=r2) with pytest.raises(ValueError): MatrixOperator(rect_mat, domain=r3, range=r3) with pytest.raises(ValueError): MatrixOperator(rect_mat, domain=r2, range=r3) # Rn to Cn okay MatrixOperator(rect_mat, domain=r3, range=odl.cn(2)) # Cn to Rn not okay (no safe cast) with pytest.raises(TypeError): MatrixOperator(rect_mat, domain=odl.cn(3), range=r2) # Complex matrix between real spaces not okay rect_complex_mat = rect_mat + 1j with pytest.raises(TypeError): MatrixOperator(rect_complex_mat, domain=r3, range=r2) # Init with array-like structure (including numpy.matrix) op = MatrixOperator(rect_mat, domain=r3, range=r2) assert isinstance(op.matrix, np.ndarray) op = MatrixOperator(np.asmatrix(rect_mat), domain=r3, range=r2) assert isinstance(op.matrix, np.ndarray) op = MatrixOperator(rect_mat.tolist(), domain=r3, range=r2) assert isinstance(op.matrix, np.ndarray) assert not op.matrix_issparse sparse_mat = _sparse_matrix(odl.rn(5)) op = MatrixOperator(sparse_mat, domain=odl.rn(5), range=odl.rn(5)) assert isinstance(op.matrix, scipy.sparse.spmatrix) assert op.matrix_issparse # Init with uniform_discr space (subclass of FnBase) dom = odl.uniform_discr(0, 1, 3) ran = odl.uniform_discr(0, 1, 2) MatrixOperator(rect_mat, domain=dom, range=ran)
def test_matrix_op_init(matrix): """Test initialization and properties of matrix operators.""" dense_matrix = matrix sparse_matrix = scipy.sparse.coo_matrix(dense_matrix) # Just check if the code runs MatrixOperator(dense_matrix) MatrixOperator(sparse_matrix) # Test default domain and range mat_op = MatrixOperator(dense_matrix) assert mat_op.domain == odl.tensor_space(4, matrix.dtype) assert mat_op.range == odl.tensor_space(3, matrix.dtype) assert np.all(mat_op.matrix == dense_matrix) sparse_matrix = scipy.sparse.coo_matrix(dense_matrix) mat_op = MatrixOperator(sparse_matrix) assert mat_op.domain == odl.tensor_space(4, matrix.dtype) assert mat_op.range == odl.tensor_space(3, matrix.dtype) assert (mat_op.matrix != sparse_matrix).getnnz() == 0 # Explicit domain and range dom = odl.tensor_space(4, matrix.dtype) ran = odl.tensor_space(3, matrix.dtype) mat_op = MatrixOperator(dense_matrix, domain=dom, range=ran) assert mat_op.domain == dom assert mat_op.range == ran mat_op = MatrixOperator(sparse_matrix, domain=dom, range=ran) assert mat_op.domain == dom assert mat_op.range == ran # Bad 1d sizes with pytest.raises(ValueError): MatrixOperator(dense_matrix, domain=odl.cn(4), range=odl.cn(4)) with pytest.raises(ValueError): MatrixOperator(dense_matrix, range=odl.cn(4)) # Invalid range dtype with pytest.raises(ValueError): MatrixOperator(dense_matrix.astype(complex), range=odl.rn(4)) # Data type promotion # real space, complex matrix -> complex space dom = odl.rn(4) mat_op = MatrixOperator(dense_matrix.astype(complex), domain=dom) assert mat_op.domain == dom assert mat_op.range == odl.cn(3) # complex space, real matrix -> complex space dom = odl.cn(4) mat_op = MatrixOperator(dense_matrix.real, domain=dom) assert mat_op.domain == dom assert mat_op.range == odl.cn(3) # Multi-dimensional spaces dom = odl.tensor_space((6, 5, 4), matrix.dtype) ran = odl.tensor_space((6, 5, 3), matrix.dtype) mat_op = MatrixOperator(dense_matrix, domain=dom, axis=2) assert mat_op.range == ran mat_op = MatrixOperator(dense_matrix, domain=dom, range=ran, axis=2) assert mat_op.range == ran with pytest.raises(ValueError): bad_dom = odl.tensor_space((6, 6, 6), matrix.dtype) # wrong shape MatrixOperator(dense_matrix, domain=bad_dom) with pytest.raises(ValueError): dom = odl.tensor_space((6, 5, 4), matrix.dtype) bad_ran = odl.tensor_space((6, 6, 6), matrix.dtype) # wrong shape MatrixOperator(dense_matrix, domain=dom, range=bad_ran) with pytest.raises(ValueError): MatrixOperator(dense_matrix, domain=dom, axis=1) with pytest.raises(ValueError): MatrixOperator(dense_matrix, domain=dom, axis=0) with pytest.raises(ValueError): bad_ran = odl.tensor_space((6, 3, 4), matrix.dtype) MatrixOperator(dense_matrix, domain=dom, range=bad_ran, axis=2) with pytest.raises(ValueError): bad_dom_for_sparse = odl.rn((6, 5, 4)) MatrixOperator(sparse_matrix, domain=bad_dom_for_sparse, axis=2) # Init with uniform_discr space (subclass of TensorSpace) dom = odl.uniform_discr(0, 1, 4, dtype=dense_matrix.dtype) ran = odl.uniform_discr(0, 1, 3, dtype=dense_matrix.dtype) MatrixOperator(dense_matrix, domain=dom, range=ran) # Make sure this runs and returns something string-like assert str(mat_op) > '' assert repr(mat_op) > ''