def __init__(self, blocks): blocks = np.array(blocks) assert isinstance(blocks, np.ndarray) and blocks.ndim == 2 self._blocks = blocks assert all( isinstance(op, OperatorInterface) for op in self._operators()) assert all( any(self._blocks[i, j] is not None for j in range(self._blocks.shape[1])) for i in range(self._blocks.shape[0])) assert all( any(self._blocks[i, j] is not None for i in range(self._blocks.shape[0])) for j in range(self._blocks.shape[1])) source_types = [None for j in range(self._blocks.shape[1])] range_types = [None for i in range(self._blocks.shape[0])] for (i, j), op in np.ndenumerate(self._blocks): if op is not None: assert source_types[j] is None or op.source == source_types[j] source_types[j] = op.source assert range_types[i] is None or op.range == range_types[i] range_types[i] = op.range self.source = VectorSpace(BlockVectorArray, tuple(source_types)) self.range = VectorSpace(BlockVectorArray, tuple(range_types)) self._source_dims = tuple(space.dim for space in self.source.subtype) self._range_dims = tuple(space.dim for space in self.range.subtype) self.num_source_blocks = len(source_types) self.num_range_blocks = len(range_types) self.linear = all(op.linear for op in self._operators()) self.build_parameter_type(inherits=list(self._operators()))
def __init__(self, op): assert isinstance(op, DiffusionOperator) self._impl = op self.source = VectorSpace(ListVectorArray, (WrappedVector, op.dim_source)) self.range = VectorSpace(ListVectorArray, (WrappedVector, op.dim_range)) self.linear = True
def __init__(self, matrix, functional=False, vector=False, solver_options=None, name=None): assert not (functional and vector) super().__init__(matrix, solver_options=solver_options, name=name) if not vector: self.source = VectorSpace(ListVectorArray, (NumpyVector, matrix.shape[1])) if not functional: self.range = VectorSpace(ListVectorArray, (NumpyVector, matrix.shape[0])) self.functional = functional self.vector = vector
def __init__(self, obj_id, operators, functionals, vector_operators, products=None, pickle_subtypes=True, array_type=MPIVectorArray): d = mpi.get_object(obj_id) visualizer = MPIVisualizer(obj_id) super().__init__(operators, functionals, vector_operators, products=products, visualizer=visualizer, cache_region=None, name=d.name) self.obj_id = obj_id subtypes = mpi.call(_MPIDiscretization_get_subtypes, obj_id, pickle_subtypes) if all(subtype == subtypes[0] for subtype in subtypes): subtypes = (subtypes[0], ) self.solution_space = VectorSpace(array_type, (d.solution_space.type, subtypes)) self.build_parameter_type(inherits=(d, )) self.parameter_space = d.parameter_space
def __init__(self, matrix, functional=False, vector=False, solver_options=None, name=None): assert not (functional and vector) super(NumpyListVectorArrayMatrixOperator, self).__init__(matrix, solver_options=solver_options, name=name) if not vector: self.source = VectorSpace(ListVectorArray, (NumpyVector, matrix.shape[1])) if not functional: self.range = VectorSpace(ListVectorArray, (NumpyVector, matrix.shape[0])) self.functional = functional self.vector = vector
def __init__(self, obj_id, functional=False, vector=False, with_apply2=False, pickle_subtypes=True, array_type=MPIVectorArray): assert not (functional and vector) self.obj_id = obj_id self.op = op = mpi.get_object(obj_id) self.functional = functional self.vector = vector self.with_apply2 = with_apply2 self.pickle_subtypes = pickle_subtypes self.array_type = array_type self.linear = op.linear self.name = op.name self.build_parameter_type(inherits=(op, )) if vector: self.source = NumpyVectorSpace(1) assert self.source == op.source else: subtypes = mpi.call(_MPIOperator_get_source_subtypes, obj_id, pickle_subtypes) if all(subtype == subtypes[0] for subtype in subtypes): subtypes = (subtypes[0], ) self.source = VectorSpace(array_type, (op.source.type, subtypes)) if functional: self.range = NumpyVectorSpace(1) assert self.range == op.range else: subtypes = mpi.call(_MPIOperator_get_range_subtypes, obj_id, pickle_subtypes) if all(subtype == subtypes[0] for subtype in subtypes): subtypes = (subtypes[0], ) self.range = VectorSpace(array_type, (op.range.type, subtypes))
def FenicsVectorSpace(V): return VectorSpace(ListVectorArray, (FenicsVector, V))
class NumpyListVectorArrayMatrixOperator(NumpyMatrixOperator): """Variant of |NumpyMatrixOperator| using |ListVectorArray| instead of |NumpyVectorArray|.""" def __init__(self, matrix, functional=False, vector=False, solver_options=None, name=None): assert not (functional and vector) super(NumpyListVectorArrayMatrixOperator, self).__init__(matrix, solver_options=solver_options, name=name) if not vector: self.source = VectorSpace(ListVectorArray, (NumpyVector, matrix.shape[1])) if not functional: self.range = VectorSpace(ListVectorArray, (NumpyVector, matrix.shape[0])) self.functional = functional self.vector = vector def apply(self, U, ind=None, mu=None): assert U in self.source assert U.check_ind(ind) if self.vector: V = super(NumpyListVectorArrayMatrixOperator, self).apply(U, ind=ind, mu=mu) return ListVectorArray([NumpyVector(v, copy=False) for v in V.data], subtype=self.range.subtype) if ind is None: vectors = U._list elif isinstance(ind, Number): vectors = [U._list[ind]] else: vectors = (U._list[i] for i in ind) V = [self._matrix.dot(v._array) for v in vectors] if self.functional: return NumpyVectorArray(V) if len(V) > 0 else self.range.empty() else: return ListVectorArray([NumpyVector(v, copy=False) for v in V], subtype=self.range.subtype) def apply_adjoint(self, U, ind=None, mu=None, source_product=None, range_product=None): raise NotImplementedError def apply_inverse(self, V, ind=None, mu=None, least_squares=False): assert V in self.range assert V.check_ind(ind) assert not self.functional and not self.vector if V.dim == 0: if self.source.dim == 0 and least_squares: return ListVectorArray( [NumpyVector(np.zeros(0), copy=False) for _ in range(V.len_ind(ind))], subtype=self.source.subtype ) else: raise InversionError options = ( self.solver_options.get("inverse") if self.solver_options else "least_squares" if least_squares else None ) if options and not least_squares: solver_type = options if isinstance(options, str) else options["type"] if solver_type.startswith("least_squares"): self.logger.warn('Least squares solver selected but "least_squares == False"') if ind is None: vectors = V._list elif isinstance(ind, Number): vectors = [V._list[ind]] else: vectors = (V._list[i] for i in ind) try: return ListVectorArray( [ NumpyVector( _apply_inverse(self._matrix, v._array.reshape((1, -1)), options=options).ravel(), copy=False ) for v in vectors ], subtype=self.source.subtype, ) except InversionError as e: if least_squares and options: solver_type = options if isinstance(options, str) else options["type"] if not solver_type.startswith("least_squares"): msg = ( str(e) + "\nNote: linear solver was selected for solving least squares problem (maybe not invertible?)" ) raise InversionError(msg) raise e def as_vector(self, mu=None): if self.source.dim != 1 and self.range.dim != 1: raise TypeError("This operator does not represent a vector or linear functional.") return ListVectorArray([NumpyVector(self._matrix.ravel(), copy=True)]) def assemble_lincomb(self, operators, coefficients, solver_options=None, name=None): lincomb = super(NumpyListVectorArrayMatrixOperator, self).assemble_lincomb(operators, coefficients) if lincomb is None: return None else: return NumpyListVectorArrayMatrixOperator(lincomb._matrix, solver_options=solver_options, name=name)
def NumpyVectorSpace(dim): """Shorthand for |VectorSpace| `(NumpyVectorArray, dim)`.""" return VectorSpace(NumpyVectorArray, dim)
class NumpyListVectorArrayMatrixOperator(NumpyMatrixOperator): """Variant of |NumpyMatrixOperator| using |ListVectorArray| instead of |NumpyVectorArray|.""" def __init__(self, matrix, functional=False, vector=False, solver_options=None, name=None): assert not (functional and vector) super().__init__(matrix, solver_options=solver_options, name=name) if not vector: self.source = VectorSpace(ListVectorArray, (NumpyVector, matrix.shape[1])) if not functional: self.range = VectorSpace(ListVectorArray, (NumpyVector, matrix.shape[0])) self.functional = functional self.vector = vector def apply(self, U, ind=None, mu=None): assert U in self.source assert U.check_ind(ind) if self.vector: V = super().apply(U, ind=ind, mu=mu) return ListVectorArray([NumpyVector(v, copy=False) for v in V.data], subtype=self.range.subtype) if ind is None: vectors = U._list elif isinstance(ind, Number): vectors = [U._list[ind]] else: vectors = (U._list[i] for i in ind) V = [self._matrix.dot(v._array) for v in vectors] if self.functional: return NumpyVectorArray(V) if len(V) > 0 else self.range.empty() else: return ListVectorArray([NumpyVector(v, copy=False) for v in V], subtype=self.range.subtype) def apply_adjoint(self, U, ind=None, mu=None, source_product=None, range_product=None): raise NotImplementedError def apply_inverse(self, V, ind=None, mu=None, least_squares=False): assert V in self.range assert V.check_ind(ind) assert not self.functional and not self.vector if V.dim == 0: if self.source.dim == 0 and least_squares: return ListVectorArray([NumpyVector(np.zeros(0), copy=False) for _ in range(V.len_ind(ind))], subtype=self.source.subtype) else: raise InversionError options = (self.solver_options.get('inverse') if self.solver_options else 'least_squares' if least_squares else None) if options and not least_squares: solver_type = options if isinstance(options, str) else options['type'] if solver_type.startswith('least_squares'): self.logger.warn('Least squares solver selected but "least_squares == False"') if ind is None: vectors = V._list elif isinstance(ind, Number): vectors = [V._list[ind]] else: vectors = (V._list[i] for i in ind) try: return ListVectorArray([NumpyVector(_apply_inverse(self._matrix, v._array.reshape((1, -1)), options=options).ravel(), copy=False) for v in vectors], subtype=self.source.subtype) except InversionError as e: if least_squares and options: solver_type = options if isinstance(options, str) else options['type'] if not solver_type.startswith('least_squares'): msg = str(e) \ + '\nNote: linear solver was selected for solving least squares problem (maybe not invertible?)' raise InversionError(msg) raise e def as_vector(self, mu=None): if self.source.dim != 1 and self.range.dim != 1: raise TypeError('This operator does not represent a vector or linear functional.') return ListVectorArray([NumpyVector(self._matrix.ravel(), copy=True)]) def assemble_lincomb(self, operators, coefficients, solver_options=None, name=None): lincomb = super().assemble_lincomb(operators, coefficients) if lincomb is None: return None else: return NumpyListVectorArrayMatrixOperator(lincomb._matrix, solver_options=solver_options, name=name)
class NumpyListVectorArrayMatrixOperator(NumpyMatrixOperator): """Variant of |NumpyMatrixOperator| using |ListVectorArray| instead of |NumpyVectorArray|.""" def __init__(self, matrix, functional=False, vector=False, name=None): assert not (functional and vector) super(NumpyListVectorArrayMatrixOperator, self).__init__(matrix, name) if not vector: self.source = VectorSpace(ListVectorArray, (NumpyVector, matrix.shape[1])) if not functional: self.range = VectorSpace(ListVectorArray, (NumpyVector, matrix.shape[0])) self.functional = functional self.vector = vector def apply(self, U, ind=None, mu=None): assert U in self.source assert U.check_ind(ind) if self.vector: V = super(NumpyListVectorArrayMatrixOperator, self).apply(U, ind=ind, mu=mu) return ListVectorArray([NumpyVector(v, copy=False) for v in V.data], subtype=self.range.subtype) if ind is None: vectors = U._list elif isinstance(ind, Number): vectors = [U._list[ind]] else: vectors = (U._list[i] for i in ind) V = [self._matrix.dot(v._array) for v in vectors] if self.functional: return NumpyVectorArray(V) if len(V) > 0 else self.range.empty() else: return ListVectorArray([NumpyVector(v, copy=False) for v in V], subtype=self.range.subtype) def apply_adjoint(self, U, ind=None, mu=None, source_product=None, range_product=None): raise NotImplementedError def apply_inverse(self, U, ind=None, mu=None, options=None): assert U in self.range assert U.check_ind(ind) assert not self.functional and not self.vector if U.dim == 0: if (self.source.dim == 0 or isinstance(options, str) and options.startswith('least_squares') or isinstance(options, dict) and options['type'].startswith('least_squares')): return ListVectorArray([NumpyVector(np.zeros(0), copy=False) for _ in range(U.len_ind(ind))], subtype=self.source.subtype) else: raise InversionError if ind is None: vectors = U._list elif isinstance(ind, Number): vectors = [U._list[ind]] else: vectors = (U._list[i] for i in ind) return ListVectorArray([NumpyVector(_apply_inverse(self._matrix, v._array, options=options), copy=False) for v in vectors], subtype=self.source.subtype) def as_vector(self, mu=None): if self.source.dim != 1 and self.range.dim != 1: raise TypeError('This operator does not represent a vector or linear functional.') return ListVectorArray([NumpyVector(self._matrix.ravel(), copy=True)]) def assemble_lincomb(self, operators, coefficients, name=None): lincomb = super(NumpyListVectorArrayMatrixOperator, self).assemble_lincomb(operators, coefficients) if lincomb is None: return None else: return NumpyListVectorArrayMatrixOperator(lincomb._matrix, name=name)