def test_static_dims_broadcast(self): # batch_shape = [2] chol = rng.rand(3, 3) rhs = rng.rand(2, 3, 7) chol_broadcast = chol + np.zeros((2, 1, 1)) result = linear_operator_util.cholesky_solve_with_broadcast(chol, rhs) self.assertAllEqual((2, 3, 7), result.get_shape()) expected = linalg_ops.cholesky_solve(chol_broadcast, rhs) self.assertAllClose(*self.evaluate([expected, result]))
def test_static_dims_broadcast(self): # batch_shape = [2] chol = rng.rand(3, 3) rhs = rng.rand(2, 3, 7) chol_broadcast = chol + np.zeros((2, 1, 1)) with self.cached_session(): result = linear_operator_util.cholesky_solve_with_broadcast(chol, rhs) self.assertAllEqual((2, 3, 7), result.get_shape()) expected = linalg_ops.cholesky_solve(chol_broadcast, rhs) self.assertAllEqual(expected.eval(), result.eval())
def _solve(self, rhs, adjoint=False, adjoint_arg=False): """Default implementation of _solve.""" if self.is_square is False: raise NotImplementedError( "Solve is not yet implemented for non-square operators.") logging.warn( "Using (possibly slow) default implementation of solve." " Requires conversion to a dense matrix and O(N^3) operations.") rhs = linalg.adjoint(rhs) if adjoint_arg else rhs if self._can_use_cholesky(): return linear_operator_util.cholesky_solve_with_broadcast( linalg_ops.cholesky(self.to_dense()), rhs) return linear_operator_util.matrix_solve_with_broadcast( self.to_dense(), rhs, adjoint=adjoint)
def _solve(self, rhs, adjoint=False, adjoint_arg=False): """Default implementation of _solve.""" if self.is_square is False: raise NotImplementedError( "Solve is not yet implemented for non-square operators.") logging.warn( "Using (possibly slow) default implementation of solve." " Requires conversion to a dense matrix and O(N^3) operations.") rhs = linalg.adjoint(rhs) if adjoint_arg else rhs if self._can_use_cholesky(): return linear_operator_util.cholesky_solve_with_broadcast( linalg_ops.cholesky(self.to_dense()), rhs) return linear_operator_util.matrix_solve_with_broadcast( self.to_dense(), rhs, adjoint=adjoint)
def test_dynamic_dims_broadcast_64bit(self): # batch_shape = [2, 2] chol = rng.rand(2, 3, 3) rhs = rng.rand(2, 1, 3, 7) chol_broadcast = chol + np.zeros((2, 2, 1, 1)) rhs_broadcast = rhs + np.zeros((2, 2, 1, 1)) chol_ph = array_ops.placeholder_with_default(chol, shape=None) rhs_ph = array_ops.placeholder_with_default(rhs, shape=None) result, expected = self.evaluate([ linear_operator_util.cholesky_solve_with_broadcast(chol_ph, rhs_ph), linalg_ops.cholesky_solve(chol_broadcast, rhs_broadcast) ]) self.assertAllClose(expected, result)
def _solve(self, rhs, adjoint=False, adjoint_arg=False): if self.base_operator.is_non_singular is False: raise ValueError( "Solve not implemented unless this is a perturbation of a " "non-singular LinearOperator.") # The Woodbury formula gives: # https://en.wikipedia.org/wiki/Woodbury_matrix_identity # (L + UDV^H)^{-1} # = L^{-1} - L^{-1} U (D^{-1} + V^H L^{-1} U)^{-1} V^H L^{-1} # = L^{-1} - L^{-1} U C^{-1} V^H L^{-1} # where C is the capacitance matrix, C := D^{-1} + V^H L^{-1} U # Note also that, with ^{-H} being the inverse of the adjoint, # (L + UDV^H)^{-H} # = L^{-H} - L^{-H} V C^{-H} U^H L^{-H} l = self.base_operator if adjoint: v = self.u u = self.v else: v = self.v u = self.u # L^{-1} rhs linv_rhs = l.solve(rhs, adjoint=adjoint, adjoint_arg=adjoint_arg) # V^H L^{-1} rhs vh_linv_rhs = linear_operator_util.matmul_with_broadcast( v, linv_rhs, adjoint_a=True) # C^{-1} V^H L^{-1} rhs if self._use_cholesky: capinv_vh_linv_rhs = linear_operator_util.cholesky_solve_with_broadcast( self._chol_capacitance, vh_linv_rhs) else: capinv_vh_linv_rhs = linear_operator_util.matrix_solve_with_broadcast( self._capacitance, vh_linv_rhs, adjoint=adjoint) # U C^{-1} V^H M^{-1} rhs u_capinv_vh_linv_rhs = linear_operator_util.matmul_with_broadcast( u, capinv_vh_linv_rhs) # L^{-1} U C^{-1} V^H L^{-1} rhs linv_u_capinv_vh_linv_rhs = l.solve(u_capinv_vh_linv_rhs, adjoint=adjoint) # L^{-1} - L^{-1} U C^{-1} V^H L^{-1} return linv_rhs - linv_u_capinv_vh_linv_rhs
def _solve(self, rhs, adjoint=False, adjoint_arg=False): if self.base_operator.is_non_singular is False: raise ValueError( "Solve not implemented unless this is a perturbation of a " "non-singular LinearOperator.") # The Woodbury formula gives: # https://en.wikipedia.org/wiki/Woodbury_matrix_identity # (L + UDV^H)^{-1} # = L^{-1} - L^{-1} U (D^{-1} + V^H L^{-1} U)^{-1} V^H L^{-1} # = L^{-1} - L^{-1} U C^{-1} V^H L^{-1} # where C is the capacitance matrix, C := D^{-1} + V^H L^{-1} U # Note also that, with ^{-H} being the inverse of the adjoint, # (L + UDV^H)^{-H} # = L^{-H} - L^{-H} V C^{-H} U^H L^{-H} l = self.base_operator if adjoint: v = self.u u = self.v else: v = self.v u = self.u # L^{-1} rhs linv_rhs = l.solve(rhs, adjoint=adjoint, adjoint_arg=adjoint_arg) # V^H L^{-1} rhs vh_linv_rhs = linear_operator_util.matmul_with_broadcast( v, linv_rhs, adjoint_a=True) # C^{-1} V^H L^{-1} rhs if self._use_cholesky: capinv_vh_linv_rhs = linear_operator_util.cholesky_solve_with_broadcast( self._chol_capacitance, vh_linv_rhs) else: capinv_vh_linv_rhs = linear_operator_util.matrix_solve_with_broadcast( self._capacitance, vh_linv_rhs, adjoint=adjoint) # U C^{-1} V^H M^{-1} rhs u_capinv_vh_linv_rhs = linear_operator_util.matmul_with_broadcast( u, capinv_vh_linv_rhs) # L^{-1} U C^{-1} V^H L^{-1} rhs linv_u_capinv_vh_linv_rhs = l.solve(u_capinv_vh_linv_rhs, adjoint=adjoint) # L^{-1} - L^{-1} U C^{-1} V^H L^{-1} return linv_rhs - linv_u_capinv_vh_linv_rhs
def test_dynamic_dims_broadcast_64bit(self): # batch_shape = [2, 2] chol = rng.rand(2, 3, 3) rhs = rng.rand(2, 1, 3, 7) chol_broadcast = chol + np.zeros((2, 2, 1, 1)) rhs_broadcast = rhs + np.zeros((2, 2, 1, 1)) chol_ph = array_ops.placeholder(dtypes.float64) rhs_ph = array_ops.placeholder(dtypes.float64) with self.cached_session() as sess: result, expected = sess.run([ linear_operator_util.cholesky_solve_with_broadcast( chol_ph, rhs_ph), linalg_ops.cholesky_solve(chol_broadcast, rhs_broadcast) ], feed_dict={ chol_ph: chol, rhs_ph: rhs, }) self.assertAllClose(expected, result)
def test_dynamic_dims_broadcast_64bit(self): # batch_shape = [2, 2] chol = rng.rand(2, 3, 3) rhs = rng.rand(2, 1, 3, 7) chol_broadcast = chol + np.zeros((2, 2, 1, 1)) rhs_broadcast = rhs + np.zeros((2, 2, 1, 1)) chol_ph = array_ops.placeholder(dtypes.float64) rhs_ph = array_ops.placeholder(dtypes.float64) with self.cached_session() as sess: result, expected = sess.run( [ linear_operator_util.cholesky_solve_with_broadcast( chol_ph, rhs_ph), linalg_ops.cholesky_solve(chol_broadcast, rhs_broadcast) ], feed_dict={ chol_ph: chol, rhs_ph: rhs, }) self.assertAllEqual(expected, result)