def _matmul(self, x, adjoint=False, adjoint_arg=False):
        # Given a Toeplitz matrix, we can embed it in a Circulant matrix to perform
        # efficient matrix multiplications. Given a Toeplitz matrix with first row
        # [t_0, t_1, ... t_{n-1}] and first column [t0, t_{-1}, ..., t_{-(n-1)},
        # let C by the circulant matrix with first column [t0, t_{-1}, ...,
        # t_{-(n-1)}, 0, t_{n-1}, ..., t_1]. Also adjoin to our input vector `x`
        # `n` zeros, to make it a vector of length `2n` (call it y). It can be shown
        # that if we take the first n entries of `Cy`, this is equal to the Toeplitz
        # multiplication. See:
        # http://math.mit.edu/icg/resources/teaching/18.085-spring2015/toeplitz.pdf
        # for more details.
        x = linalg.adjoint(x) if adjoint_arg else x
        expanded_x = array_ops.concat([x, array_ops.zeros_like(x)], axis=-2)
        col = ops.convert_to_tensor(self.col)
        row = ops.convert_to_tensor(self.row)
        circulant_col = array_ops.concat([
            col,
            array_ops.zeros_like(col[..., 0:1]),
            array_ops.reverse(row[..., 1:], axis=[-1])
        ],
                                         axis=-1)
        circulant = linear_operator_circulant.LinearOperatorCirculant(
            fft_ops.fft(_to_complex(circulant_col)),
            input_output_dtype=row.dtype)
        result = circulant.matmul(expanded_x,
                                  adjoint=adjoint,
                                  adjoint_arg=False)

        shape = self._shape_tensor(row=row, col=col)
        return math_ops.cast(
            result[..., :self._domain_dimension_tensor(shape=shape), :],
            self.dtype)
def _inverse_circulant(circulant_operator):
    # Inverting the spectrum is sufficient to get the inverse.
    return linear_operator_circulant.LinearOperatorCirculant(
        spectrum=1. / circulant_operator.spectrum,
        is_non_singular=circulant_operator.is_non_singular,
        is_self_adjoint=circulant_operator.is_self_adjoint,
        is_positive_definite=circulant_operator.is_positive_definite,
        is_square=True)
def _matmul_linear_operator_circulant_circulant(linop_a, linop_b):
    return linear_operator_circulant.LinearOperatorCirculant(
        spectrum=linop_a.spectrum * linop_b.spectrum,
        is_non_singular=_combined_non_singular_hint(linop_a, linop_b),
        is_self_adjoint=_combined_self_adjoint_hint(linop_a, linop_b),
        is_positive_definite=_combined_positive_definite_hint(
            linop_a, linop_b),
        is_square=True)
  def __init__(self,
               col,
               row,
               is_non_singular=None,
               is_self_adjoint=None,
               is_positive_definite=None,
               is_square=None,
               name="LinearOperatorToeplitz"):
    r"""Initialize a `LinearOperatorToeplitz`.

    Args:
      col: Shape `[B1,...,Bb, N]` `Tensor` with `b >= 0` `N >= 0`.
        The first column of the operator. Allowed dtypes: `float16`, `float32`,
          `float64`, `complex64`, `complex128`. Note that the first entry of
          `col` is assumed to be the same as the first entry of `row`.
      row: Shape `[B1,...,Bb, N]` `Tensor` with `b >= 0` `N >= 0`.
        The first row of the operator. Allowed dtypes: `float16`, `float32`,
          `float64`, `complex64`, `complex128`. Note that the first entry of
          `row` is assumed to be the same as the first entry of `col`.
      is_non_singular:  Expect that this operator is non-singular.
      is_self_adjoint:  Expect that this operator is equal to its hermitian
        transpose.  If `diag.dtype` is real, this is auto-set to `True`.
      is_positive_definite:  Expect that this operator is positive definite,
        meaning the quadratic form `x^H A x` has positive real part for all
        nonzero `x`.  Note that we do not require the operator to be
        self-adjoint to be positive-definite.  See:
        https://en.wikipedia.org/wiki/Positive-definite_matrix#Extension_for_non-symmetric_matrices
      is_square:  Expect that this operator acts like square [batch] matrices.
      name: A name for this `LinearOperator`.
    """

    with ops.name_scope(name, values=[row, col]):
      self._row = ops.convert_to_tensor(row, name="row")
      self._col = ops.convert_to_tensor(col, name="col")
      self._check_row_col(self._row, self._col)

      circulant_col = array_ops.concat(
          [self._col,
           array_ops.zeros_like(self._col[..., 0:1]),
           array_ops.reverse(self._row[..., 1:], axis=[-1])], axis=-1)

      # To be used for matmul.
      self._circulant = linear_operator_circulant.LinearOperatorCirculant(
          fft_ops.fft(_to_complex(circulant_col)),
          input_output_dtype=self._row.dtype)

      if is_square is False:  # pylint:disable=g-bool-id-comparison
        raise ValueError("Only square Toeplitz operators currently supported.")
      is_square = True

      super(LinearOperatorToeplitz, self).__init__(
          dtype=self._row.dtype,
          graph_parents=[self._row, self._col],
          is_non_singular=is_non_singular,
          is_self_adjoint=is_self_adjoint,
          is_positive_definite=is_positive_definite,
          is_square=is_square,
          name=name)
def _solve_linear_operator_circulant_circulant(linop_a, linop_b):
    return linear_operator_circulant.LinearOperatorCirculant(
        spectrum=linop_b.spectrum / linop_a.spectrum,
        is_non_singular=registrations_util.combined_non_singular_hint(
            linop_a, linop_b),
        is_self_adjoint=registrations_util.
        combined_commuting_self_adjoint_hint(linop_a, linop_b),
        is_positive_definite=(
            registrations_util.combined_commuting_positive_definite_hint(
                linop_a, linop_b)),
        is_square=True)
Exemple #6
0
def _adjoint_circulant(circulant_operator):
    spectrum = circulant_operator.spectrum
    if spectrum.dtype.is_complex:
        spectrum = math_ops.conj(spectrum)

    # Conjugating the spectrum is sufficient to get the adjoint.
    return linear_operator_circulant.LinearOperatorCirculant(
        spectrum=spectrum,
        is_non_singular=circulant_operator.is_non_singular,
        is_self_adjoint=circulant_operator.is_self_adjoint,
        is_positive_definite=circulant_operator.is_positive_definite,
        is_square=True)
def _operator_from_kernel(kernel, d, **kwargs):
    spectrum = linear_operator_circulant._FFT_OP[d](math_ops.cast(
        kernel, dtypes.complex64))
    if d == 1:
        return linear_operator_circulant.LinearOperatorCirculant(
            spectrum, **kwargs)
    elif d == 2:
        return linear_operator_circulant.LinearOperatorCirculant2D(
            spectrum, **kwargs)
    elif d == 3:
        return linear_operator_circulant.LinearOperatorCirculant3D(
            spectrum, **kwargs)