Source code for openmdao.matrices.coo_matrix
"""Define the COOmatrix class."""
import numpy as np
from scipy.sparse import coo_matrix
from openmdao.core.constants import INT_DTYPE
from openmdao.matrices.matrix import Matrix
[docs]class COOMatrix(Matrix):
"""
Sparse matrix in Coordinate list format.
Used with the SplitJacobian to represent the dr/do and dr/di matrices, to form a matvec
product with the d_outputs and d_inputs vectors respectively.
Parameters
----------
submats : dict
Dictionary of sub-jacobian data keyed by (row_name, col_name).
Attributes
----------
_coo : coo_matrix
COO matrix. Used as a basis for conversion to CSC, CSR, Dense in inherited classes.
_matrix_T : sparse matrix
Transpose of the matrix. Only computed if needed for reverse mode for CSC or CSR
matrices.
_coo_slices : dict
Dictionary of slices into the COO matrix data/rows/cols for each sub-jacobian.
"""
[docs] def __init__(self, submats):
"""
Initialize all attributes.
"""
super().__init__(submats)
self._coo = None
self._matrix_T = None
self._coo_slices = {}
def _build(self, num_rows, num_cols, dtype=float):
"""
Allocate the matrix.
Also, keep track of the slice within the COO data/rows/cols arrays corresponding to each
sub-jacobian.
Parameters
----------
num_rows : int
number of rows in the matrix.
num_cols : int
number of cols in the matrix.
dtype : dtype
The dtype of the matrix.
"""
submats = self._submats
self._coo_slices = {}
rows = []
cols = []
# compute the ranges of the subjacs within the COO data/rows/cols arrays
start = end = 0
for key, submat in submats.items():
_, r, c = submat.as_coo_info(full=True)
end += r.size
rows.append(r)
cols.append(c)
self._coo_slices[key] = slice(start, end)
start = end
rows = np.concatenate(rows, dtype=INT_DTYPE)
cols = np.concatenate(cols, dtype=INT_DTYPE)
data = np.zeros(end, dtype=dtype)
self._matrix = self._coo = coo_matrix((data, (rows, cols)), shape=(num_rows, num_cols))
[docs] def transpose(self):
"""
Transpose the matrix.
Returns
-------
coo_matrix
Transposed matrix.
"""
return self._matrix.T
def _prod(self, in_vec, mode, mask=None):
"""
Perform a matrix vector product.
Parameters
----------
in_vec : ndarray
incoming vector to multiply.
mode : str
'fwd' or 'rev'.
mask : ndarray or None
Array used to mask out part of the vector. If mask is not None then
the masked values will be set to 0.0.
Returns
-------
ndarray
vector resulting from the product.
"""
if mode == 'fwd':
return self._matrix @ self._get_masked_arr(in_vec, mask)
else: # rev
return self.transpose() @ self._get_masked_arr(in_vec, mask)
def _update_dtype(self, dtype):
"""
Update the dtype of the matrix.
This happens during pre_update.
Parameters
----------
dtype : dtype
The new dtype of the matrix.
"""
if dtype.kind != self.dtype.kind:
self.dtype = dtype
data = self._coo.data if dtype.kind == 'c' else self._coo.data.real
self._coo.data = np.ascontiguousarray(data, dtype=dtype)
self._matrix_T = None
def _update_from_submat(self, subjac, randgen):
"""
Update the matrix from a sub-jacobian.
"""
self._coo.data[self._coo_slices[subjac.key]] = subjac.get_as_coo_data(randgen)
if subjac.factor is not None:
self._coo.data[self._coo_slices[subjac.key]] *= subjac.factor
[docs] def todense(self):
"""
Return a dense version of the matrix.
Returns
-------
ndarray
Dense array representation of the matrix.
"""
return self._coo.toarray()
[docs] def dump(self, msginfo):
"""
Dump the matrix to stdout.
Parameters
----------
msginfo : str
Message info.
"""
print(f"{msginfo}: COOMatrix:")
for r, c, v in sorted(zip(self._coo.row, self._coo.col, self._coo.data)):
print(f"{r}, {c}, {v}")