Transform [batch] matrix `x` with left multiplication: `x --> Ax`. ```python # Make an operator acting like batch matrix A. Assume A.shape = [..., M, N] operator = LinearOperator(...) operator.shape = [..., M, N] X = ... # shape [..., N, R], batch matrix, R > 0. Y = oper
(self, x, adjoint=False, adjoint_arg=False, name="matmul")
| 573 | raise NotImplementedError("_matmul is not implemented.") |
| 574 | |
| 575 | def matmul(self, x, adjoint=False, adjoint_arg=False, name="matmul"): |
| 576 | """Transform [batch] matrix `x` with left multiplication: `x --> Ax`. |
| 577 | |
| 578 | ```python |
| 579 | # Make an operator acting like batch matrix A. Assume A.shape = [..., M, N] |
| 580 | operator = LinearOperator(...) |
| 581 | operator.shape = [..., M, N] |
| 582 | |
| 583 | X = ... # shape [..., N, R], batch matrix, R > 0. |
| 584 | |
| 585 | Y = operator.matmul(X) |
| 586 | Y.shape |
| 587 | ==> [..., M, R] |
| 588 | |
| 589 | Y[..., :, r] = sum_j A[..., :, j] X[j, r] |
| 590 | ``` |
| 591 | |
| 592 | Args: |
| 593 | x: `LinearOperator` or `Tensor` with compatible shape and same `dtype` as |
| 594 | `self`. See class docstring for definition of compatibility. |
| 595 | adjoint: Python `bool`. If `True`, left multiply by the adjoint: `A^H x`. |
| 596 | adjoint_arg: Python `bool`. If `True`, compute `A x^H` where `x^H` is |
| 597 | the hermitian transpose (transposition and complex conjugation). |
| 598 | name: A name for this `Op`. |
| 599 | |
| 600 | Returns: |
| 601 | A `LinearOperator` or `Tensor` with shape `[..., M, R]` and same `dtype` |
| 602 | as `self`. |
| 603 | """ |
| 604 | if isinstance(x, LinearOperator): |
| 605 | left_operator = self.adjoint() if adjoint else self |
| 606 | right_operator = x.adjoint() if adjoint_arg else x |
| 607 | |
| 608 | if (right_operator.range_dimension is not None and |
| 609 | left_operator.domain_dimension is not None and |
| 610 | right_operator.range_dimension != left_operator.domain_dimension): |
| 611 | raise ValueError( |
| 612 | "Operators are incompatible. Expected `x` to have dimension" |
| 613 | " {} but got {}.".format( |
| 614 | left_operator.domain_dimension, right_operator.range_dimension)) |
| 615 | with self._name_scope(name): |
| 616 | return linear_operator_algebra.matmul(left_operator, right_operator) |
| 617 | |
| 618 | with self._name_scope(name): |
| 619 | x = ops.convert_to_tensor(x, name="x") |
| 620 | self._check_input_dtype(x) |
| 621 | |
| 622 | self_dim = -2 if adjoint else -1 |
| 623 | arg_dim = -1 if adjoint_arg else -2 |
| 624 | tensor_shape.dimension_at_index( |
| 625 | self.shape, self_dim).assert_is_compatible_with( |
| 626 | x.shape[arg_dim]) |
| 627 | |
| 628 | return self._matmul(x, adjoint=adjoint, adjoint_arg=adjoint_arg) |
| 629 | |
| 630 | def _matvec(self, x, adjoint=False): |
| 631 | x_mat = array_ops.expand_dims(x, axis=-1) |