def _cond(self):
        if not self.is_self_adjoint:
            # In general the condition number is the ratio of the
            # absolute value of the largest and smallest singular values.
            vals = linalg_ops.svd(self.to_dense(), compute_uv=False)
        else:
            # For self-adjoint matrices, and in general normal matrices,
            # we can use eigenvalues.
            vals = math_ops.abs(self._eigvals())

        return (math_ops.reduce_max(vals, axis=-1) /
                math_ops.reduce_min(vals, axis=-1))
Exemple #2
0
def assert_no_entries_with_modulus_zero(
    x, message=None, name="assert_no_entries_with_modulus_zero"):
  """Returns `Op` that asserts Tensor `x` has no entries with modulus zero.

  Args:
    x:  Numeric `Tensor`, real, integer, or complex.
    message:  A string message to prepend to failure message.
    name:  A name to give this `Op`.

  Returns:
    An `Op` that asserts `x` has no entries with modulus zero.
  """
  with ops.name_scope(name, values=[x]):
    x = ops.convert_to_tensor(x, name="x")
    dtype = x.dtype
    should_be_nonzero = math_ops.abs(x)
    zero = ops.convert_to_tensor(0, dtype=dtypes.real_dtype(dtype))
    return check_ops.assert_less(zero, should_be_nonzero, message=message)
Exemple #3
0
    def _log_abs_determinant(self):
        # Recall
        #   det(L + UDV^H) = det(D^{-1} + V^H L^{-1} U) det(D) det(L)
        #                  = det(C) det(D) det(L)
        log_abs_det_d = self.diag_operator.log_abs_determinant()
        log_abs_det_l = self.base_operator.log_abs_determinant()

        if self._use_cholesky:
            chol_cap_diag = _linalg.diag_part(self._chol_capacitance)
            log_abs_det_c = 2 * math_ops.reduce_sum(
                math_ops.log(chol_cap_diag), axis=[-1])
        else:
            det_c = linalg_ops.matrix_determinant(self._capacitance)
            log_abs_det_c = math_ops.log(math_ops.abs(det_c))
            if np.issubdtype(self.dtype, np.complexfloating):
                log_abs_det_c = _ops.cast(log_abs_det_c, dtype=self.dtype)

        return log_abs_det_c + log_abs_det_d + log_abs_det_l
Exemple #4
0
    def assert_hermitian_spectrum(self, name="assert_hermitian_spectrum"):
        """Returns an `Op` that asserts this operator has Hermitian spectrum.

    This operator corresponds to a real-valued matrix if and only if its
    spectrum is Hermitian.

    Args:
      name:  A name to give this `Op`.

    Returns:
      An `Op` that asserts this operator has Hermitian spectrum.
    """
        eps = np.finfo(dtypes.real_dtype(self.dtype)).eps
        with self._name_scope(name):  # pylint: disable=not-callable
            # Assume linear accumulation of error.
            max_err = eps * self.domain_dimension_tensor()
            imag_convolution_kernel = math_ops.imag(self.convolution_kernel())
            return check_ops.assert_less(math_ops.abs(imag_convolution_kernel),
                                         max_err,
                                         message="Spectrum was not Hermitian")
 def _log_abs_determinant(self):
     return self._num_rows_cast_to_real_dtype * math_ops.log(
         math_ops.abs(self.multiplier))
 def _assert_non_singular(self):
     return check_ops.assert_positive(math_ops.abs(self.multiplier),
                                      message="LinearOperator was singular")
Exemple #7
0
 def _log_abs_determinant(self):
     axis = [-(i + 1) for i in range(self.block_depth)]
     lad = math_ops.reduce_sum(math_ops.log(math_ops.abs(self.spectrum)),
                               axis=axis)
     return _ops.cast(lad, self.dtype)
 def _log_abs_determinant(self):
   return math_ops.reduce_sum(
       math_ops.log(math_ops.abs(self._get_diag())), axis=[-1])
 def _cond(self):
     abs_diag = math_ops.abs(self.diag)
     return (math_ops.reduce_max(abs_diag, axis=-1) /
             math_ops.reduce_min(abs_diag, axis=-1))
 def _log_abs_determinant(self):
     log_det = math_ops.reduce_sum(math_ops.log(math_ops.abs(self._diag)),
                                   axis=[-1])
     if np.issubdtype(self.dtype, np.complexfloating):
         log_det = _ops.cast(log_det, dtype=self.dtype)
     return log_det
Exemple #11
0
  def __init__(self,
               spectrum,
               block_depth,
               input_output_dtype=dtypes.complex64,
               is_non_singular=None,
               is_self_adjoint=None,
               is_positive_definite=None,
               is_square=True,
               name="LinearOperatorCirculant"):
    r"""Initialize an `_BaseLinearOperatorCirculant`.

    Args:
      spectrum:  Shape `[B1,...,Bb, N]` `Tensor`.  Allowed dtypes: `float16`,
        `float32`, `float64`, `complex64`, `complex128`.  Type can be different
        than `input_output_dtype`
      block_depth:  Python integer, either 1, 2, or 3.  Will be 1 for circulant,
        2 for block circulant, and 3 for nested block circulant.
      input_output_dtype: `dtype` for input/output.
      is_non_singular:  Expect that this operator is non-singular.
      is_self_adjoint:  Expect that this operator is equal to its hermitian
        transpose.  If `spectrum` is real, this will always be 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 to prepend to all ops created by this class.

    Raises:
      ValueError:  If `block_depth` is not an allowed value.
      TypeError:  If `spectrum` is not an allowed type.
    """

    allowed_block_depths = [1, 2, 3]

    self._name = name

    if block_depth not in allowed_block_depths:
      raise ValueError("Expected block_depth to be in %s.  Found: %s." %
                       (allowed_block_depths, block_depth))
    self._block_depth = block_depth

    with ops.name_scope(name, values=[spectrum]):
      self._spectrum = self._check_spectrum_and_return_tensor(spectrum)

      # Check and auto-set hints.
      if not np.issubdtype(self.spectrum.dtype, np.complexfloating):
        if is_self_adjoint is False:
          raise ValueError(
              "A real spectrum always corresponds to a self-adjoint operator.")
        is_self_adjoint = True

      if is_square is False:
        raise ValueError(
            "A [[nested] block] circulant operator is always square.")
      is_square = True

      # If _ops.TensorShape(spectrum.shape) = [s0, s1, s2], and block_depth = 2,
      # block_shape = [s1, s2]
      s_shape = array_ops.shape(self.spectrum)
      self._block_shape_tensor = s_shape[-self.block_depth:]

      # Add common variants of spectrum to the graph.
      self._spectrum_complex = _to_complex(self.spectrum)
      self._abs_spectrum = math_ops.abs(self.spectrum)
      self._conj_spectrum = math_ops.conj(self._spectrum_complex)

      super(_BaseLinearOperatorCirculant, self).__init__(
          dtype=dtypes.as_dtype(input_output_dtype),
          graph_parents=[self.spectrum],
          is_non_singular=is_non_singular,
          is_self_adjoint=is_self_adjoint,
          is_positive_definite=is_positive_definite,
          is_square=is_square,
          name=name)