def _matvec(self, x): from bempp.api.utils.data_types import combined_type if x.ndim == 1: x_new = _np.expand_dims(x, 1) return self.matvec(x_new).ravel() if not self._fill_complete(): raise ValueError("Not all rows or columns contain operators.") row_dim = 0 res = _np.zeros((self.shape[0], x.shape[1]), dtype=combined_type(self.dtype, x.dtype)) for i in range(self._m): col_dim = 0 local_res = res[row_dim:row_dim + self._rows[i], :] for j in range(self._n): local_x = x[col_dim:col_dim + self._cols[j], :] if self._operators[i, j] is not None: op_is_complex = _np.iscomplexobj(self._operators[i, j].dtype.type(1)) if _np.iscomplexobj(x) and not op_is_complex: local_res[:] += (self._operators[i, j] * _np.real(local_x) + 1j * self._operators[i, j] * _np.imag(local_x)) else: local_res[:] += self._operators[i, j].dot(local_x) col_dim += self._cols[j] row_dim += self._rows[i] return res
def _matvec(self, x): from bempp.api.utils.data_types import combined_type expand_input_dim = False if x.ndim == 1: x_new = _np.expand_dims(x, 1) expand_input_dim = True return self.matvec(x_new).ravel() if not self._fill_complete(): raise ValueError("Not all rows or columns contain operators.") row_dim = 0 res = _np.zeros((self.shape[0], x.shape[1]), dtype=combined_type(self.dtype, x.dtype)) for i in range(self.ndims[0]): col_dim = 0 local_res = res[row_dim:row_dim + self._rows[i], :] for j in range(self.ndims[1]): local_x = x[col_dim:col_dim + self._cols[j], :] op_is_complex = _np.iscomplexobj( self._operators[i, j].dtype.type(1)) if _np.iscomplexobj(x) and not op_is_complex: local_res[:] += ( self._operators[i, j].dot(_np.real(local_x)) + 1j * self._operators[i, j].dot(_np.imag(local_x))) else: local_res[:] += self._operators[i, j].dot(local_x) col_dim += self._cols[j] row_dim += self._rows[i] if expand_input_dim: return res.ravel() else: return res
def _matmat(self, x): from bempp.api.utils.data_types import combined_type if not self._fill_complete(): raise ValueError("Not all rows or columns contain operators.") row_dim = 0 res = _np.zeros((self.shape[0], x.shape[1]), dtype=combined_type(self.dtype, x.dtype)) for i in range(self._ndims[0]): col_dim = 0 local_res = res[row_dim:row_dim + self._rows[i], :] for j in range(self._ndims[1]): local_x = x[col_dim:col_dim + self._cols[j], :] op_is_complex = _np.iscomplexobj( self._operators[i, j].dtype.type(1)) if _np.iscomplexobj(x) and not op_is_complex: local_res[:] += self._operators[i, j].dot( _np.real(local_x)) + 1j * self._operators[i, j].dot( _np.imag(local_x)) else: local_res[:] += self._operators[i, j].dot(local_x) col_dim += self._cols[j] row_dim += self._rows[i] return res
def _get_dtype(self): from bempp.api.utils.data_types import combined_type d = 'float64' for obj in self._operators.ravel(): if obj is not None: d = combined_type(d, obj.dtype) return d
def __init__(self, op1, op2): """Construct a product of the form op1 * op2.""" if _np.any(op1.column_dimensions != op2.row_dimensions): raise ValueError("Incompatible dimensions. {0} != {1}".format( op1.column_dimensions, op2.row_dimensions)) self._op1 = op1 self._op2 = op2 from bempp.api.utils.data_types import combined_type super(BlockedDiscreteOperatorProduct, self).__init__(op1.ndims[0], op2.ndims[1], combined_type(op1.dtype, op2.dtype), (op1.shape[0], op2.shape[1]))
def _matvec(self, x): """Perform matrix vector multiplication.""" from bempp.api.utils.data_types import combined_type if not self._fill_complete(): raise ValueError("Not all rows or columns contain operators.") ndims = len(x.shape) x = x.ravel() row_dim = 0 res = _np.zeros(self.shape[0], dtype=combined_type(self.dtype, x.dtype)) compute_tasks = [] # Submit the computations for i in range(self._ndims[0]): col_dim = 0 for j in range(self._ndims[1]): if self._tags[i, j] != -1: # If self._tags[i, j] == -1 the operator is None local_x = x[col_dim:col_dim + self._cols[j]] compute_tasks.append((self._operators[i, j], local_x)) col_dim += self._cols[j] row_dim += self._rows[i] # Execute computations compute_results = self._manager.compute_parallel(compute_tasks) # Get results back row_dim = 0 task_count = 0 for i in range(self._ndims[0]): col_dim = 0 for j in range(self._ndims[1]): if self._tags[i, j] == -1: continue res[row_dim:row_dim + self._rows[i]] += compute_results[task_count] task_count += 1 row_dim += self._rows[i] if ndims == 2: res = res.reshape(-1, 1) return res
def _matmat(self, other): """Implement the matrix/vector product.""" from bempp.api.utils.data_types import combined_type row_count = 0 output = _np.zeros( (self.shape[0], other.shape[1]), dtype=combined_type(self.dtype, other.dtype), ) for row in self._operators: row_dim = row[0].shape[0] column_count = 0 for elem in row: output[row_count:row_count + row_dim, :] += ( elem @ other[column_count:column_count + elem.shape[1], :]) column_count += elem.shape[1] row_count += row_dim return output
def __init__(self, operators): """Initialize a generalized blocked operator.""" from bempp.api.utils.data_types import combined_type self._operators = operators row_dimensions = [] shape = [0, 0] # Get column dimension for elem in operators[0]: shape[1] += elem.shape[1] # Get row dimension for row in operators: shape[0] += row[0].shape[0] shape = tuple(shape) # Get dtype dtype = operators[0][0].dtype for row in operators: for elem in row: dtype = combined_type(dtype, elem.dtype) # Sanity check of dimensions for row in operators: row_dim = row[0].shape[0] column_dim = 0 for elem in row: if elem.shape[0] != row_dim: raise ValueError("Incompatible dimensions detected.") column_dim += elem.shape[1] if column_dim != shape[1]: raise ValueError("Incompatible dimensions detected.") super().__init__(dtype, shape)
def __init__(self, ops): """ Construct an operator from a two dimensional Numpy array of operators. ops is a list of list containing discrete boundary operators or None. A None entry is equivalent to a zero discrete boundary operator. """ # pylint: disable=too-many-branches from bempp.api.utils.data_types import combined_type from bempp.api.assembly.discrete_boundary_operator import ( ZeroDiscreteBoundaryOperator, ) if not isinstance(ops, _np.ndarray): ops = _np.array(ops) rows = ops.shape[0] cols = ops.shape[1] self._ndims = (rows, cols) self._operators = _np.empty((rows, cols), dtype=_np.object) self._rows = -_np.ones(rows, dtype=int) self._cols = -_np.ones(cols, dtype=int) for i in range(rows): for j in range(cols): if ops[i, j] is None: continue if self._rows[i] != -1: if ops[i, j].shape[0] != self._rows[i]: raise ValueError( "Block row {0} has incompatible ".format(i) + " operator sizes.") else: self._rows[i] = ops[i, j].shape[0] if self._cols[j] != -1: if ops[i, j].shape[1] != self._cols[j]: raise ValueError( "Block column {0} has incompatible".format(j) + "operator sizes.") else: self._cols[j] = ops[i, j].shape[1] self._operators[i, j] = ops[i, j] if not self._fill_complete(): raise ValueError( "Each row and column must contain at least one operator.") for i in range(rows): for j in range(cols): if self._operators[i, j] is None: self._operators[i, j] = ZeroDiscreteBoundaryOperator( self._rows[i], self._cols[j]) shape = (_np.sum(self._rows), _np.sum(self._cols)) dtype = "float32" for obj in self._operators.ravel(): if obj is not None: dtype = combined_type(dtype, obj.dtype) super().__init__(dtype, shape)