def test_to_matrix(): np.random.seed(0) A = np.random.randn(2, 2) B = np.random.randn(3, 3) C = np.random.randn(3, 3) X = np.bmat([[np.eye(2) + A, np.zeros((2, 3))], [np.zeros((3, 2)), B.dot(C.T)]]) C = sps.csc_matrix(C) Aop = NumpyMatrixOperator(A) Bop = NumpyMatrixOperator(B) Cop = NumpyMatrixOperator(C) Xop = BlockDiagonalOperator([ LincombOperator([IdentityOperator(NumpyVectorSpace(2)), Aop], [1, 1]), Concatenation(Bop, AdjointOperator(Cop)) ]) assert np.allclose(X, to_matrix(Xop)) assert np.allclose(X, to_matrix(Xop, format='csr').toarray()) np.random.seed(0) V = np.random.randn(10, 2) Vva = NumpyVectorArray(V.T) Vop = VectorArrayOperator(Vva) assert np.allclose(V, to_matrix(Vop)) Vop = VectorArrayOperator(Vva, transposed=True) assert np.allclose(V, to_matrix(Vop).T)
def action_apply_basis(self, op): range_basis, source_basis = self.range_basis, self.source_basis if source_basis is None: try: V = op.apply_adjoint(range_basis) except NotImplementedError: raise RuleNotMatchingError('apply_adjoint not implemented') if isinstance(op.source, NumpyVectorSpace): from pymor.operators.numpy import NumpyMatrixOperator return NumpyMatrixOperator(V.to_numpy(), source_id=op.source.id, name=op.name) else: from pymor.operators.constructions import VectorArrayOperator return VectorArrayOperator(V, adjoint=True, name=op.name) else: if range_basis is None: V = op.apply(source_basis) if isinstance(op.range, NumpyVectorSpace): from pymor.operators.numpy import NumpyMatrixOperator return NumpyMatrixOperator(V.to_numpy().T, range_id=op.range.id, name=op.name) else: from pymor.operators.constructions import VectorArrayOperator return VectorArrayOperator(V, adjoint=False, name=op.name) else: from pymor.operators.numpy import NumpyMatrixOperator return NumpyMatrixOperator(op.apply2(range_basis, source_basis), name=op.name)
def test_vectorarray_op_apply_inverse(): np.random.seed(1234) O = np.random.random((5, 5)) op = VectorArrayOperator(NumpyVectorSpace.make_array(O)) V = op.range.random() U = op.apply_inverse(V) v = V.to_numpy() u = np.linalg.solve(O.T, v.ravel()) assert np.all(almost_equal(U, U.space.from_numpy(u)))
def test_adjoint_vectorarray_op_apply_inverse_lstsq(): np.random.seed(1234) O = np.random.random((3, 5)) op = VectorArrayOperator(NumpyVectorSpace.make_array(O), adjoint=True) V = op.range.random() U = op.apply_inverse(V, least_squares=True) v = V.to_numpy() u = np.linalg.lstsq(O, v.ravel())[0] assert np.all(almost_equal(U, U.space.from_numpy(u)))
def test_to_matrix_VectorArrayOperator(): np.random.seed(0) V = np.random.randn(10, 2) Vva = NumpyVectorSpace.make_array(V.T) Vop = VectorArrayOperator(Vva) assert_type_and_allclose(V, Vop, 'dense') Vop = VectorArrayOperator(Vva, transposed=True) assert_type_and_allclose(V.T, Vop, 'dense')
def projected(self, range_basis, source_basis, product=None, name=None): name = name or '{}_projected'.format(self.name) if self.linear and not self.parametric: assert source_basis is None or source_basis in self.source assert range_basis is None or range_basis in self.range assert product is None or product.source == product.range == self.range if source_basis is None: if range_basis is None: return self else: try: V = self.apply_adjoint(range_basis, range_product=product) except NotImplementedError: return ProjectedOperator(self, range_basis, None, product, name=name) if self.source.type == NumpyVectorArray: from pymor.operators.numpy import NumpyMatrixOperator return NumpyMatrixOperator(V.data, name=name) else: from pymor.operators.constructions import VectorArrayOperator return VectorArrayOperator(V, transposed=True, name=name) else: if range_basis is None: V = self.apply(source_basis) if self.range.type == NumpyVectorArray: from pymor.operators.numpy import NumpyMatrixOperator return NumpyMatrixOperator(V.data.T, name=name) else: from pymor.operators.constructions import VectorArrayOperator return VectorArrayOperator(V, transposed=False, name=name) elif product is None: from pymor.operators.numpy import NumpyMatrixOperator return NumpyMatrixOperator(self.apply2( range_basis, source_basis), name=name) else: from pymor.operators.numpy import NumpyMatrixOperator V = self.apply(source_basis) return NumpyMatrixOperator(product.apply2(range_basis, V), name=name) else: self.logger.warn('Using inefficient generic projection operator') return ProjectedOperator(self, range_basis, source_basis, product, name=name)
def projected(self, source_basis, range_basis, product=None, name=None): name = name or '{}_projected'.format(self.name) if self.linear and not self.parametric: assert source_basis is None or source_basis in self.source assert range_basis is None or range_basis in self.range assert product is None or product.source == product.range == self.range if source_basis is None: if range_basis is None: return self else: V = self.apply_adjoint(range_basis, range_product=product) if self.source.type == NumpyVectorArray: from pymor.operators.numpy import NumpyMatrixOperator return NumpyMatrixOperator(V.data, name=name) else: from pymor.operators.constructions import VectorArrayOperator return VectorArrayOperator(V, transposed=True, copy=False, name=name) else: if range_basis is None: V = self.apply(source_basis) if self.range.type == NumpyVectorArray: from pymor.operators.numpy import NumpyMatrixOperator return NumpyMatrixOperator(V.data.T, name=name) else: from pymor.operators.constructions import VectorArrayOperator return VectorArrayOperator(V, transposed=False, copy=False, name=name) elif product is None: from pymor.operators.numpy import NumpyMatrixOperator return NumpyMatrixOperator(self.apply2(range_basis, source_basis, pairwise=False), name=name) else: from pymor.operators.numpy import NumpyMatrixOperator V = self.apply(source_basis) return NumpyMatrixOperator(product.apply2(range_basis, V, pairwise=False), name=name) else: self.logger.warn('Using inefficient generic projection operator') # Since the bases are not immutable and we do not own them, # the ProjectedOperator will have to create copies of them. return ProjectedOperator(self, source_basis, range_basis, product, copy=True, name=name)
def action_apply_basis(self, op): range_basis, source_basis, product = self.range_basis, self.source_basis, self.product if source_basis is None: if range_basis is None: return op else: try: V = op.apply_transpose( product.apply(range_basis) if product else range_basis) except NotImplementedError: raise RuleNotMatchingError( 'apply_transpose not implemented') if isinstance(op.source, NumpyVectorSpace): from pymor.operators.numpy import NumpyMatrixOperator return NumpyMatrixOperator(V.data, source_id=op.source.id, range_id=op.range.id, name=op.name) else: from pymor.operators.constructions import VectorArrayOperator return VectorArrayOperator(V, transposed=True, space_id=op.range.id, name=op.name) else: if range_basis is None: V = op.apply(source_basis) if isinstance(op.range, NumpyVectorSpace): from pymor.operators.numpy import NumpyMatrixOperator return NumpyMatrixOperator(V.data.T, source_id=op.source.id, range_id=op.range.id, name=op.name) else: from pymor.operators.constructions import VectorArrayOperator return VectorArrayOperator(V, transposed=False, space_id=op.source.id, name=op.name) elif product is None: from pymor.operators.numpy import NumpyMatrixOperator return NumpyMatrixOperator(op.apply2(range_basis, source_basis), source_id=op.source.id, range_id=op.range.id, name=op.name) else: from pymor.operators.numpy import NumpyMatrixOperator V = op.apply(source_basis) return NumpyMatrixOperator(product.apply2(range_basis, V), source_id=op.source.id, range_id=op.range.id, name=op.name)
def jacobian(self, U, mu=None): mu = self.parse_parameter(mu) if len(self.interpolation_dofs) == 0: if self.source.type == self.range.type == NumpyVectorArray: return NumpyMatrixOperator(np.zeros((0, self.source.dim)), name=self.name + '_jacobian') else: return ZeroOperator(self.source, self.range, name=self.name + '_jacobian') elif hasattr(self, 'operator'): return EmpiricalInterpolatedOperator(self.operator.jacobian(U, mu=mu), self.interpolation_dofs, self.collateral_basis, self.triangular, self.name + '_jacobian') else: U_components = NumpyVectorArray(U.components(self.source_dofs), copy=False) JU = self.restricted_operator.jacobian(U_components, mu=mu) \ .apply(NumpyVectorArray(np.eye(len(self.source_dofs)), copy=False)) try: if self.triangular: interpolation_coefficients = solve_triangular(self.interpolation_matrix, JU.data.T, lower=True, unit_diagonal=True).T else: interpolation_coefficients = np.linalg.solve(self.interpolation_matrix, JU._array.T).T except ValueError: # this exception occurs when AU contains NaNs ... interpolation_coefficients = np.empty((len(JU), len(self.collateral_basis))) + np.nan J = self.collateral_basis.lincomb(interpolation_coefficients) if isinstance(J, NumpyVectorArray): J = NumpyMatrixOperator(J.data.T) else: J = VectorArrayOperator(J, copy=False) return Concatenation(J, ComponentProjection(self.source_dofs, self.source), name=self.name + '_jacobian')
def jacobian(self, U, mu=None): mu = self.parse_parameter(mu) options = self.solver_options.get('jacobian') if self.solver_options else None if len(self.interpolation_dofs) == 0: if isinstance(self.source, NumpyVectorSpace) and isinstance(self.range, NumpyVectorSpace): return NumpyMatrixOperator(np.zeros((self.range.dim, self.source.dim)), solver_options=options, source_id=self.source.id, range_id=self.range.id, name=self.name + '_jacobian') else: return ZeroOperator(self.range, self.source, name=self.name + '_jacobian') elif hasattr(self, 'operator'): return EmpiricalInterpolatedOperator(self.operator.jacobian(U, mu=mu), self.interpolation_dofs, self.collateral_basis, self.triangular, solver_options=options, name=self.name + '_jacobian') else: restricted_source = self.restricted_operator.source U_dofs = restricted_source.make_array(U.dofs(self.source_dofs)) JU = self.restricted_operator.jacobian(U_dofs, mu=mu) \ .apply(restricted_source.make_array(np.eye(len(self.source_dofs)))) try: if self.triangular: interpolation_coefficients = solve_triangular(self.interpolation_matrix, JU.to_numpy().T, lower=True, unit_diagonal=True).T else: interpolation_coefficients = solve(self.interpolation_matrix, JU.to_numpy().T).T except ValueError: # this exception occurs when AU contains NaNs ... interpolation_coefficients = np.empty((len(JU), len(self.collateral_basis))) + np.nan J = self.collateral_basis.lincomb(interpolation_coefficients) if isinstance(J.space, NumpyVectorSpace): J = NumpyMatrixOperator(J.to_numpy().T, range_id=self.range.id) else: J = VectorArrayOperator(J) return Concatenation([J, ComponentProjection(self.source_dofs, self.source)], solver_options=options, name=self.name + '_jacobian')
def mpi_wrap_operator(obj_id, mpi_range, mpi_source, with_apply2=False, pickle_local_spaces=True, space_type=MPIVectorSpace): """Wrap MPI distributed local |Operators| to a global |Operator| on rank 0. Given MPI distributed local |Operators| referred to by the :class:`~pymor.tools.mpi.ObjectId` `obj_id`, return a new |Operator| which manages these distributed operators from rank 0. This is done by instantiating :class:`MPIOperator`. Additionally, the structure of the wrapped operators is preserved. E.g. |LincombOperators| will be wrapped as a |LincombOperator| of :class:`MPIOperators <MPIOperator>`. Parameters ---------- See :class:`MPIOperator`. Returns ------- The wrapped |Operator|. """ op = mpi.get_object(obj_id) if isinstance(op, LincombOperator): obj_ids = mpi.call(_mpi_wrap_operator_LincombOperator_manage_operators, obj_id) return LincombOperator([mpi_wrap_operator(o, mpi_range, mpi_source, with_apply2, pickle_local_spaces, space_type) for o in obj_ids], op.coefficients, name=op.name) elif isinstance(op, VectorArrayOperator): array_obj_id, local_spaces = mpi.call(_mpi_wrap_operator_VectorArrayOperator_manage_array, obj_id, pickle_local_spaces) if all(ls == local_spaces[0] for ls in local_spaces): local_spaces = (local_spaces[0],) return VectorArrayOperator(space_type(local_spaces).make_array(array_obj_id), adjoint=op.adjoint, name=op.name) else: return MPIOperator(obj_id, mpi_range, mpi_source, with_apply2, pickle_local_spaces, space_type)
def jacobian(self, U, mu=None): assert len(U) == 1 assert self.parameters.assert_compatible(mu) options = self.solver_options.get( 'jacobian') if self.solver_options else None if self.interpolation_matrix.shape[0] == 0: return NumpyMatrixOperator(np.zeros( (self.range.dim, self.source.dim)), solver_options=options, name=self.name + '_jacobian') U_dofs = self.source_basis_dofs.lincomb(U.to_numpy()[0]) J = self.restricted_operator.jacobian(U_dofs, mu=mu).apply( self.source_basis_dofs) try: if self.triangular: interpolation_coefficients = solve_triangular( self.interpolation_matrix, J.to_numpy().T, lower=True, unit_diagonal=True).T else: interpolation_coefficients = solve(self.interpolation_matrix, J.to_numpy().T).T except ValueError: # this exception occurs when J contains NaNs ... interpolation_coefficients = (np.empty( (len(self.source_basis_dofs), len(self.projected_collateral_basis))) + np.nan) M = self.projected_collateral_basis.lincomb(interpolation_coefficients) if isinstance(M.space, NumpyVectorSpace): return NumpyMatrixOperator(M.to_numpy().T, solver_options=options) else: assert not options return VectorArrayOperator(M)
def thermalblock_vectorarray_factory(adjoint, xblocks, yblocks, diameter, seed): from pymor.operators.constructions import VectorArrayOperator _, _, U, V, sp, rp = thermalblock_factory(xblocks, yblocks, diameter, seed) op = VectorArrayOperator(U, adjoint) if adjoint: U = V V = op.range.make_array(np.random.random((7, op.range.dim))) sp = rp rp = NumpyMatrixOperator(np.eye(op.range.dim) * 2) else: U = op.source.make_array(np.random.random((7, op.source.dim))) sp = NumpyMatrixOperator(np.eye(op.source.dim) * 2) return op, None, U, V, sp, rp
def thermalblock_vectorarray_factory(transposed, xblocks, yblocks, diameter, seed): from pymor.operators.constructions import VectorArrayOperator _, _, U, V, sp, rp = thermalblock_factory(xblocks, yblocks, diameter, seed) op = VectorArrayOperator(U, transposed) if transposed: U = V V = NumpyVectorArray(np.random.random((7, op.range.dim)), copy=False) sp = rp rp = NumpyMatrixOperator(np.eye(op.range.dim) * 2) else: U = NumpyVectorArray(np.random.random((7, op.source.dim)), copy=False) sp = NumpyMatrixOperator(np.eye(op.source.dim) * 2) return op, None, U, V, sp, rp
def mpi_wrap_operator(obj_id, functional=False, vector=False, with_apply2=False, pickle_subtypes=True, array_type=MPIVectorArray): """Wrap MPI distributed local |Operators| to a global |Operator| on rank 0. Given MPI distributed local |Operators| referred to by the `~pymor.tools.mpi.ObjectId` `obj_id`, return a new |Operator| which manages these distributed operators from rank 0. This is done by instantiating :class:`MPIOperator`. Additionally, the structure of the wrapped operators is preserved. E.g. |LincombOperators| will be wrapped as a |LincombOperator| of :class:`MPIOperators`. Parameters ---------- See :class:`MPIOperator`. Returns ------- The wrapped |Operator|. """ op = mpi.get_object(obj_id) if isinstance(op, LincombOperator): obj_ids = mpi.call(_mpi_wrap_operator_LincombOperator_manage_operators, obj_id) return LincombOperator([ mpi_wrap_operator(o, functional, vector, with_apply2, pickle_subtypes, array_type) for o in obj_ids ], op.coefficients, name=op.name) elif isinstance(op, VectorArrayOperator): array_obj_id, subtypes = mpi.call( _mpi_wrap_operator_VectorArrayOperator_manage_array, obj_id, pickle_subtypes) if all(subtype == subtypes[0] for subtype in subtypes): subtypes = (subtypes[0], ) return VectorArrayOperator(array_type(type(op._array), subtypes, array_obj_id), transposed=op.transposed, name=op.name) else: return MPIOperator(obj_id, functional, vector, with_apply2, pickle_subtypes, array_type)
def action_VectorArrayOperator(self, ops): if not all(op.adjoint == ops[0].adjoint for op in ops): raise RuleNotMatchingError adjoint = ops[0].adjoint assert not self.solver_options coeffs = np.conj(self.coefficients) if adjoint else self.coefficients if coeffs[0] == 1: array = ops[0]._array.copy() else: array = ops[0]._array * coeffs[0] for op, c in zip(ops[1:], coeffs[1:]): array.axpy(c, op._array) return VectorArrayOperator(array, adjoint=adjoint, space_id=ops[0].space_id, name=self.name)
def jacobian(self, U, mu=None): assert len(U) == 1 mu = self.parse_parameter(mu) U_components = self.source_basis_dofs.lincomb(U.data[0]) J = self.restricted_operator.jacobian(U_components, mu=mu).apply(self.source_basis_dofs) try: if self.triangular: interpolation_coefficients = solve_triangular(self.interpolation_matrix, J.data.T, lower=True, unit_diagonal=True).T else: interpolation_coefficients = np.linalg.solve(self.interpolation_matrix, J.data.T).T except ValueError: # this exception occurs when J contains NaNs ... interpolation_coefficients = (np.empty((len(self.projected_collateral_basis), len(self.source_basis_dofs))) + np.nan) M = self.projected_collateral_basis.lincomb(interpolation_coefficients) if isinstance(M, NumpyVectorArray): return NumpyMatrixOperator(M.data.T) else: return VectorArrayOperator(M)
def localize_operator(self, op, range_ind, source_ind): if isinstance(op, VectorArrayOperator): assert range_ind is None source_ind = tuple(source_ind) source_subspace = self.join_spaces(source_ind) a = NumpyVectorSpace.make_array(op._array.data[:, source_subspace]) result = VectorArrayOperator(a, transposed=op.transposed, name='{}-{}-{}'.format( op.name, source_ind, range_ind)) return result if isinstance(op, NumpyMatrixOperator): # special case for functionals if range_ind is None: source_ind = tuple(source_ind) source_subspace = self.join_spaces(source_ind) m = op.matrix[source_subspace] result = NumpyMatrixOperator(m, name='{}-{}-{}'.format( op.name, source_ind, range_ind)) return result source_ind = tuple(source_ind) range_ind = tuple(range_ind) op_id = getattr(op, 'sid', op.uid) identification_key = (op_id, source_ind, range_ind) if identification_key in self._resultcache: return self._resultcache[identification_key] if op_id not in self._non_zeros: # FIXME also handle dense case M = op.matrix.tocoo() incidences = np.empty(len(M.col), dtype=[('row', np.int32), ('col', np.int32)]) incidences['row'] = self.subspace_map[M.row] incidences['col'] = self.subspace_map[M.col] incidences = np.unique(incidences) self._non_zeros[op_id] = set(incidences.tolist()) non_zeros = self._non_zeros[op_id] if all((ri, si) not in non_zeros for si, ri in product(source_ind, range_ind)): return None source_subspace = self.join_spaces(source_ind) range_subspace = self.join_spaces(range_ind) if issparse(op.matrix): m = op.matrix.tocsc()[:, source_subspace][range_subspace, :] else: m = op.matrix[:, source_subspace][range_subspace, :] result = NumpyMatrixOperator(m, name='{}-{}-{}'.format( op.name, source_ind, range_ind)) self._resultcache[identification_key] = result return result elif isinstance(op, LincombOperator): ops = [ self.localize_operator(o, range_ind, source_ind) for o in op.operators ] return LincombOperator(ops, op.coefficients) else: print("op is ", op) raise NotImplementedError
from pymor.algorithms.randrangefinder import rrf, adaptive_rrf from pymor.operators.numpy import NumpyMatrixOperator from pymor.operators.constructions import VectorArrayOperator np.random.seed(0) A = uniform(low=-1.0, high=1.0, size=(100, 100)) A = A.dot(A.T) range_product = NumpyMatrixOperator(A) np.random.seed(1) A = uniform(low=-1.0, high=1.0, size=(10, 10)) A = A.dot(A.T) source_product = NumpyMatrixOperator(A) B = range_product.range.random(10, seed=10) op = VectorArrayOperator(B) C = range_product.range.random( 10, seed=11) + 1j * range_product.range.random(10, seed=12) op_complex = VectorArrayOperator(C) def test_rrf(): Q = rrf(op, source_product, range_product) assert Q in op.range assert len(Q) == 8 Q = rrf(op_complex, iscomplex=True) assert np.iscomplexobj(Q.data) assert Q in op.range assert len(Q) == 8