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 _ops.cast(
            result[..., :self._domain_dimension_tensor(shape=shape), :],
            self.dtype)
Esempio n. 2
0
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,
        input_output_dtype=circulant_operator.dtype)
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=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)
def _adjoint_circulant(circulant_operator):
  spectrum = circulant_operator.spectrum
  if np.issubdtype(spectrum.dtype, np.complexfloating):
    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)