def testNonSquareMatrix(self):
   with self.assertRaises(ValueError):
     linalg_ops.cholesky(np.array([[1., 2., 3.], [3., 4., 5.]]))
   with self.assertRaises(ValueError):
     linalg_ops.cholesky(
         np.array([[[1., 2., 3.], [3., 4., 5.]], [[1., 2., 3.], [3., 4., 5.]]
                  ]))
  def benchmarkCholeskyOp(self):
    for shape in self.shapes:
      with ops.Graph().as_default(), \
          session.Session() as sess, \
          ops.device("/cpu:0"):
        matrix = variables.Variable(self._GenerateMatrix(shape))
        l = linalg_ops.cholesky(matrix)
        variables.global_variables_initializer().run()
        self.run_op_benchmark(
            sess,
            control_flow_ops.group(
                l,),
            min_iters=25,
            name="cholesky_cpu_{shape}".format(shape=shape))

      if test.is_gpu_available(True):
        with ops.Graph().as_default(), \
            session.Session() as sess, \
            ops.device("/device:GPU:0"):
          matrix = variables.Variable(self._GenerateMatrix(shape))
          l = linalg_ops.cholesky(matrix)
          variables.global_variables_initializer().run()
          self.run_op_benchmark(
              sess,
              control_flow_ops.group(
                  l,),
              min_iters=25,
              name="cholesky_gpu_{shape}".format(shape=shape))
 def testWrongDimensions(self):
   for dtype in self.float_types:
     tensor3 = constant_op.constant([1., 2.], dtype=dtype)
     with self.assertRaises(ValueError):
       linalg_ops.cholesky(tensor3)
     with self.assertRaises(ValueError):
       linalg_ops.cholesky(tensor3)
 def testNonSquareMatrix(self):
   for dtype in self.float_types:
     with self.assertRaises(ValueError):
       linalg_ops.cholesky(np.array([[1., 2., 3.], [3., 4., 5.]], dtype=dtype))
     with self.assertRaises(ValueError):
       linalg_ops.cholesky(
           np.array(
               [[[1., 2., 3.], [3., 4., 5.]], [[1., 2., 3.], [3., 4., 5.]]],
               dtype=dtype))
 def testConcurrentExecutesWithoutError(self):
   with self.test_session(use_gpu=True) as sess:
     matrix1 = random_ops.random_normal([5, 5], seed=42)
     matrix2 = random_ops.random_normal([5, 5], seed=42)
     matrix1 = math_ops.matmul(matrix1, matrix1, adjoint_a=True)
     matrix2 = math_ops.matmul(matrix2, matrix2, adjoint_a=True)
     c1 = linalg_ops.cholesky(matrix1)
     c2 = linalg_ops.cholesky(matrix2)
     c1_val, c2_val = sess.run([c1, c2])
     self.assertAllEqual(c1_val, c2_val)
Example #6
0
 def _variance(self):
     x = math_ops.sqrt(self.df) * self._square_scale_operator()
     d = array_ops.expand_dims(array_ops.matrix_diag_part(x), -1)
     v = math_ops.square(x) + math_ops.matmul(d, d, adjoint_b=True)
     if self.cholesky_input_output_matrices:
         return linalg_ops.cholesky(v)
     return v
  def _overdetermined(op, grad):
    """Gradients for the overdetermined case of MatrixSolveLs.

    This is the backprop for the solution to the normal equations of the first
    kind:
       X = F(A, B) = (A^T * A + lambda * I)^{-1} * A^T * B
    which solve the least squares problem
       min ||A * X - B||_F^2 + lambda ||X||_F^2.
    """
    a = op.inputs[0]
    b = op.inputs[1]
    l2_regularizer = op.inputs[2]
    x = op.outputs[0]
    a_shape = array_ops.shape(a)
    batch_shape = a_shape[:-2]
    n = a_shape[-1]

    identity = linalg_ops.eye(n, batch_shape=batch_shape, dtype=a.dtype)
    gramian = math_ops.batch_matmul(
        a, a, adj_x=True) + l2_regularizer * identity
    chol = linalg_ops.cholesky(gramian)
    # Temporary z = (A^T * A + lambda * I)^{-1} * grad.
    z = linalg_ops.cholesky_solve(chol, grad)
    xzt = math_ops.batch_matmul(x, z, adj_y=True)
    zx_sym = xzt + array_ops.matrix_transpose(xzt)
    grad_a = -math_ops.batch_matmul(a, zx_sym) + math_ops.batch_matmul(
        b, z, adj_y=True)
    grad_b = math_ops.batch_matmul(a, z)
    return (grad_a, grad_b, None)
  def _underdetermined(op, grad):
    """Gradients for the underdetermined case of MatrixSolveLs.

    This is the backprop for the solution to the normal equations of the second
    kind:
      X = F(A, B) = A * (A*A^T + lambda*I)^{-1} * B
    that (for lambda=0) solve the least squares problem
      min ||X||_F subject to A*X = B.
    """
    a = op.inputs[0]
    b = op.inputs[1]
    l2_regularizer = op.inputs[2]
    a_shape = array_ops.shape(a)
    batch_shape = a_shape[:-2]
    m = a_shape[-2]

    identity = linalg_ops.eye(m, batch_shape=batch_shape, dtype=a.dtype)
    gramian = math_ops.batch_matmul(
        a, a, adj_y=True) + l2_regularizer * identity
    chol = linalg_ops.cholesky(gramian)
    grad_b = linalg_ops.cholesky_solve(chol, math_ops.batch_matmul(a, grad))
    # Temporary z = (A * A^T + lambda * I)^{-1} * B.
    z = linalg_ops.cholesky_solve(chol, b)
    bz = -math_ops.batch_matmul(grad_b, z, adj_y=True)
    bz_sym = bz + array_ops.matrix_transpose(bz)
    grad_a = math_ops.batch_matmul(bz_sym, a) + math_ops.batch_matmul(z, grad)
    return (grad_a, grad_b, None)
Example #9
0
 def _verifyCholesky(self, x):
     # Verify that LL^T == x.
     chol = linalg_ops.cholesky(x)
     verification = test_util.matmul_without_tf32(chol,
                                                  chol,
                                                  adjoint_b=True)
     self._verifyCholeskyBase(x, chol, verification)
Example #10
0
    def _underdetermined(op, grad):
        """Gradients for the underdetermined case of MatrixSolveLs.

    This is the backprop for the solution to the normal equations of the second
    kind:
      X = F(A, B) = A * (A*A^T + lambda*I)^{-1} * B
    that (for lambda=0) solve the least squares problem
      min ||X||_F subject to A*X = B.
    """
        a = op.inputs[0]
        b = op.inputs[1]
        l2_regularizer = math_ops.cast(op.inputs[2], a.dtype.base_dtype)
        a_shape = array_ops.shape(a)
        batch_shape = a_shape[:-2]
        m = a_shape[-2]

        identity = linalg_ops.eye(m, batch_shape=batch_shape, dtype=a.dtype)
        gramian = math_ops.batch_matmul(a, a,
                                        adj_y=True) + l2_regularizer * identity
        chol = linalg_ops.cholesky(gramian)
        grad_b = linalg_ops.cholesky_solve(chol,
                                           math_ops.batch_matmul(a, grad))
        # Temporary tmp = (A * A^T + lambda * I)^{-1} * B.
        tmp = linalg_ops.cholesky_solve(chol, b)
        a1 = math_ops.batch_matmul(tmp, a, adj_x=True)
        a1 = -math_ops.batch_matmul(grad_b, a1)
        a2 = grad - math_ops.batch_matmul(a, grad_b, adj_x=True)
        a2 = math_ops.batch_matmul(tmp, a2, adj_y=True)
        grad_a = a1 + a2
        return (grad_a, grad_b, None)
Example #11
0
  def _overdetermined(op, grad):
    """Gradients for the overdetermined case of MatrixSolveLs.

    This is the backprop for the solution to the normal equations of the first
    kind:
       X = F(A, B) = (A^T * A + lambda * I)^{-1} * A^T * B
    which solve the least squares problem
       min ||A * X - B||_F^2 + lambda ||X||_F^2.
    """
    a = op.inputs[0]
    b = op.inputs[1]
    l2_regularizer = math_ops.cast(op.inputs[2], a.dtype.base_dtype)
    x = op.outputs[0]
    a_shape = array_ops.shape(a)
    batch_shape = a_shape[:-2]
    n = a_shape[-1]

    identity = linalg_ops.eye(n, batch_shape=batch_shape, dtype=a.dtype)
    gramian = math_ops.matmul(a, a, adjoint_a=True) + l2_regularizer * identity
    chol = linalg_ops.cholesky(gramian)
    # Temporary z = (A^T * A + lambda * I)^{-1} * grad.
    z = linalg_ops.cholesky_solve(chol, grad)
    xzt = math_ops.matmul(x, z, adjoint_b=True)
    zx_sym = xzt + array_ops.matrix_transpose(xzt)
    grad_a = -math_ops.matmul(a, zx_sym) + math_ops.matmul(b, z, adjoint_b=True)
    grad_b = math_ops.matmul(a, z)
    return (grad_a, grad_b, None)
Example #12
0
 def _variance(self):
   x = math_ops.sqrt(self.df) * self.scale_operator_pd.to_dense()
   d = array_ops.expand_dims(array_ops.matrix_diag_part(x), -1)
   v = math_ops.square(x) + math_ops.matmul(d, d, adjoint_b=True)
   if self.cholesky_input_output_matrices:
     return linalg_ops.cholesky(v)
   return v
Example #13
0
  def _underdetermined(op, grad):
    """Gradients for the underdetermined case of MatrixSolveLs.

    This is the backprop for the solution to the normal equations of the second
    kind:
      X = F(A, B) = A * (A*A^T + lambda*I)^{-1} * B
    that (for lambda=0) solve the least squares problem
      min ||X||_F subject to A*X = B.
    """
    a = op.inputs[0]
    b = op.inputs[1]
    l2_regularizer = math_ops.cast(op.inputs[2], a.dtype.base_dtype)
    a_shape = array_ops.shape(a)
    batch_shape = a_shape[:-2]
    m = a_shape[-2]

    identity = linalg_ops.eye(m, batch_shape=batch_shape, dtype=a.dtype)
    gramian = math_ops.matmul(a, a, adjoint_b=True) + l2_regularizer * identity
    chol = linalg_ops.cholesky(gramian)
    grad_b = linalg_ops.cholesky_solve(chol, math_ops.matmul(a, grad))
    # Temporary tmp = (A * A^T + lambda * I)^{-1} * B.
    tmp = linalg_ops.cholesky_solve(chol, b)
    a1 = math_ops.matmul(tmp, a, adjoint_a=True)
    a1 = -math_ops.matmul(grad_b, a1)
    a2 = grad - math_ops.matmul(a, grad_b, adjoint_a=True)
    a2 = math_ops.matmul(tmp, a2, adjoint_b=True)
    grad_a = a1 + a2
    return (grad_a, grad_b, None)
    def runFiniteDifferences(self, shapes, dtypes=(dtypes_lib.float32, dtypes_lib.float64), scalarTest=False):
        with self.test_session(use_gpu=False):
            for shape in shapes:
                for batch in False, True:
                    for dtype in dtypes:
                        if not scalarTest:
                            x = constant_op.constant(np.random.randn(shape[0], shape[1]), dtype)
                            tensor = math_ops.matmul(x, array_ops.transpose(x)) / shape[0]
                        else:
                            # This is designed to be a faster test for larger matrices.
                            x = constant_op.constant(np.random.randn(), dtype)
                            R = constant_op.constant(np.random.randn(shape[0], shape[1]), dtype)
                            e = math_ops.mul(R, x)
                            tensor = math_ops.matmul(e, array_ops.transpose(e)) / shape[0]

                        # Inner-most matrices in tensor are positive definite.
                        if batch:
                            tensor = array_ops.tile(array_ops.expand_dims(tensor, 0), [4, 1, 1])
                        y = linalg_ops.cholesky(tensor)
                        if scalarTest:
                            y = math_ops.reduce_mean(y)
                        error = gradient_checker.compute_gradient_error(x, x._shape_as_list(), y, y._shape_as_list())
                        tf_logging.info("error = %f", error)
                        if dtype == dtypes_lib.float64:
                            self.assertLess(error, 1e-5)
                        else:
                            self.assertLess(error, 3e-3)
Example #15
0
 def _verifyCholesky(self, x):
     # Verify that LL^T == x.
     # rocBLAS on ROCm stack does not support complex<float> dgemv yet
     with self.cached_session(
             use_gpu=True and not test.is_built_with_rocm()) as sess:
         chol = linalg_ops.cholesky(x)
         verification = math_ops.matmul(chol, chol, adjoint_b=True)
         self._verifyCholeskyBase(sess, x, chol, verification)
 def _verifyCholesky(self, x, atol=1e-6):
   # Verify that LL^T == x.
   with self.test_session() as sess:
     placeholder = array_ops.placeholder(
         dtypes.as_dtype(x.dtype), shape=x.shape)
     with self.test_scope():
       chol = linalg_ops.cholesky(placeholder)
     verification = math_ops.matmul(chol, chol, adjoint_b=True)
     self._verifyCholeskyBase(sess, placeholder, x, chol, verification, atol)
Example #17
0
 def _log_abs_determinant(self):
   logging.warn(
       "Using (possibly slow) default implementation of determinant."
       "  Requires conversion to a dense matrix and O(N^3) operations.")
   if self._can_use_cholesky():
     diag = array_ops.matrix_diag_part(linalg_ops.cholesky(self.to_dense()))
     return 2 * math_ops.reduce_sum(math_ops.log(diag), axis=[-1])
   _, log_abs_det = linalg.slogdet(self.to_dense())
   return log_abs_det
Example #18
0
 def _verifyCholesky(self, x, atol=1e-6):
   # Verify that LL^T == x.
   with self.session() as sess:
     placeholder = array_ops.placeholder(
         dtypes.as_dtype(x.dtype), shape=x.shape)
     with self.test_scope():
       chol = linalg_ops.cholesky(placeholder)
     verification = test_util.matmul_without_tf32(chol, chol, adjoint_b=True)
     self._verifyCholeskyBase(sess, placeholder, x, chol, verification, atol)
 def _log_abs_determinant(self):
   logging.warn(
       "Using (possibly slow) default implementation of determinant."
       "  Requires conversion to a dense matrix and O(N^3) operations.")
   if self._can_use_cholesky():
     diag = array_ops.matrix_diag_part(linalg_ops.cholesky(self.to_dense()))
     return 2 * math_ops.reduce_sum(math_ops.log(diag), axis=[-1])
   _, log_abs_det = linalg.slogdet(self.to_dense())
   return log_abs_det
Example #20
0
 def test_cholesky(self):
   with self.test_session(graph=ops.Graph()) as sess:
     sess.graph.seed = random_seed.DEFAULT_GRAPH_SEED
     operator, mat = self.operator_and_matrix(
         shapes_info, dtype, use_placeholder=use_placeholder,
         ensure_self_adjoint_and_pd=True)
     op_chol = operator.cholesky().to_dense()
     mat_chol = linalg_ops.cholesky(mat)
     op_chol_v, mat_chol_v = sess.run([op_chol, mat_chol])
     self.assertAC(mat_chol_v, op_chol_v)
 def test_cholesky(self):
   with self.test_session(graph=ops.Graph()) as sess:
     sess.graph.seed = random_seed.DEFAULT_GRAPH_SEED
     operator, mat = self.operator_and_matrix(
         shapes_info, dtype, use_placeholder=use_placeholder,
         ensure_self_adjoint_and_pd=True)
     op_chol = operator.cholesky().to_dense()
     mat_chol = linalg_ops.cholesky(mat)
     op_chol_v, mat_chol_v = sess.run([op_chol, mat_chol])
     self.assertAC(mat_chol_v, op_chol_v)
Example #22
0
 def _dense_solve(self, rhs, adjoint=False, adjoint_arg=False):
     """Solve by conversion to a dense matrix."""
     if self.is_square is False:  # pylint: disable=g-bool-id-comparison
         raise NotImplementedError(
             "Solve is not yet implemented for non-square operators.")
     rhs = linalg.adjoint(rhs) if adjoint_arg else rhs
     if self._can_use_cholesky():
         return linalg_ops.cholesky_solve(
             linalg_ops.cholesky(self.to_dense()), rhs)
     return linear_operator_util.matrix_solve_with_broadcast(
         self.to_dense(), rhs, adjoint=adjoint)
 def testNotInvertibleCpu(self):
   # Non-invertible inputs result in lower-triangular NaNs.
   x = constant_op.constant([[1., -1., 0.], [-1., 1., -1.], [0., -1., 1.]])
   chol = linalg_ops.cholesky(x)
   # Extract the lower-triangular elements.
   lower_mask = array_ops.matrix_band_part(
       constant_op.constant(True, shape=x.shape), -1, 0)
   chol_lower = array_ops.boolean_mask(chol, lower_mask)
   # Assert all NaN.
   all_nan = self.evaluate(
       math_ops.reduce_all(math_ops.reduce_all(math_ops.is_nan(chol_lower))))
   self.assertTrue(all_nan)
Example #24
0
 def _solve(self, rhs, adjoint=False, adjoint_arg=False):
     """Default implementation of _solve."""
     if self.is_square is False:
         raise NotImplementedError(
             "Solve is not yet implemented for non-square operators.")
     logging.warn(
         "Using (possibly slow) default implementation of solve."
         "  Requires conversion to a dense matrix and O(N^3) operations.")
     rhs = linalg.adjoint(rhs) if adjoint_arg else rhs
     if self._can_use_cholesky():
         return linalg_ops.cholesky_solve(
             linalg_ops.cholesky(self.to_dense()), rhs)
     return linalg_ops.matrix_solve(self.to_dense(), rhs, adjoint=adjoint)
Example #25
0
  def benchmarkCholeskyOp(self):
    for size in self.sizes:
      data = self._GenerateData(size)

      with ops.Graph().as_default(), \
          session.Session() as sess, \
          ops.device("/cpu:0"):
        l = linalg_ops.cholesky(data)
        self.run_op_benchmark(
            sess, control_flow_ops.group(l,),
            min_iters=25,
            name="cholesky_cpu_{size}".format(size=size))

      if test.is_gpu_available(True):
        with ops.Graph().as_default(), \
            session.Session() as sess, \
            ops.device("/gpu:0"):
          l = linalg_ops.cholesky(data)
          self.run_op_benchmark(
              sess, l,
              min_iters=25,
              name="cholesky_gpu_{size}".format(size=size))
 def Compute(x):
   # Turn the random matrix x into a Hermitian matrix by
   # computing the quadratic form x * x^H.
   a = test_util.matmul_without_tf32(
       x, math_ops.conj(array_ops.matrix_transpose(x))) / shape[0]
   if batch:
     a = array_ops.tile(array_ops.expand_dims(a, 0), [2, 1, 1])
   # Finally take the cholesky decomposition of the Hermitian matrix.
   c = linalg_ops.cholesky(a)
   if scalar_test:
     # Reduce to a single scalar output to speed up test.
     c = math_ops.reduce_mean(c)
   return c
  def testAgainstSpecialized(self):
    np.random.seed(0)
    data = np.random.randn(33, 33).astype(np.float32)
    data = np.matmul(data, data.T)
    grad_data = np.random.randn(*data.shape).astype(np.float32)

    with ops.Graph().as_default(), self.test_session(use_gpu=False) as s:
      x = constant_op.constant(data, dtypes_lib.float32)
      chol = linalg_ops.cholesky(x)
      composite_grad = gradients_impl.gradients(chol, x, grad_data)[0]
      specialized_grad = SpecializedGrad(chol, grad_data)
      reference, actual = s.run([specialized_grad, composite_grad])
    self.assertAllClose(reference, actual)
Example #28
0
    def __init__(self,
                 df,
                 scale,
                 cholesky_input_output_matrices=False,
                 validate_args=False,
                 allow_nan_stats=True,
                 name="WishartFull"):
        """Construct Wishart distributions.

    Args:
      df: `float` or `double` `Tensor`. Degrees of freedom, must be greater than
        or equal to dimension of the scale matrix.
      scale: `float` or `double` `Tensor`. The symmetric positive definite
        scale matrix of the distribution.
      cholesky_input_output_matrices: Python `bool`. Any function which whose
        input or output is a matrix assumes the input is Cholesky and returns a
        Cholesky factored matrix. Example `log_prob` input takes a Cholesky and
        `sample_n` returns a Cholesky when
        `cholesky_input_output_matrices=True`.
      validate_args: Python `bool`, default `False`. When `True` distribution
        parameters are checked for validity despite possibly degrading runtime
        performance. When `False` invalid inputs may silently render incorrect
        outputs.
      allow_nan_stats: Python `bool`, default `True`. When `True`, statistics
        (e.g., mean, mode, variance) use the value "`NaN`" to indicate the
        result is undefined. When `False`, an exception is raised if one or
        more of the statistic's batch members are undefined.
      name: Python `str` name prefixed to Ops created by this class.
    """
        parameters = dict(locals())
        with ops.name_scope(name) as name:
            with ops.name_scope("init", values=[scale]):
                scale = ops.convert_to_tensor(scale)
                if validate_args:
                    scale = distribution_util.assert_symmetric(scale)
                chol = linalg_ops.cholesky(scale)
                chol = control_flow_ops.with_dependencies([
                    check_ops.assert_positive(array_ops.matrix_diag_part(chol))
                ] if validate_args else [], chol)
        super(WishartFull, self).__init__(
            df=df,
            scale_operator=linalg.LinearOperatorLowerTriangular(
                tril=chol,
                is_non_singular=True,
                is_positive_definite=True,
                is_square=True),
            cholesky_input_output_matrices=cholesky_input_output_matrices,
            validate_args=validate_args,
            allow_nan_stats=allow_nan_stats,
            name=name)
        self._parameters = parameters
    def __init__(self,
                 matrix,
                 is_non_singular=None,
                 is_self_adjoint=None,
                 is_positive_definite=None,
                 name="LinearOperatorMatrix"):
        """Initialize a `LinearOperatorMatrix`.

    Args:
      matrix:  Shape `[B1,...,Bb, M, N]` with `b >= 0`, `M, N >= 0`.
        Allowed dtypes: `float32`, `float64`, `complex64`, `complex128`.
      is_non_singular:  Expect that this operator is non-singular.
      is_self_adjoint:  Expect that this operator is equal to its hermitian
        transpose.
      is_positive_definite:  Expect that this operator is positive definite,
        meaning the real part of all eigenvalues is positive.  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
      name: A name for this `LinearOperator`.

    Raises:
      TypeError:  If `diag.dtype` is not an allowed type.
    """

        allowed_dtypes = [
            dtypes.float32, dtypes.float64, dtypes.complex64, dtypes.complex128
        ]

        with ops.name_scope(name, values=[matrix]):
            self._matrix = ops.convert_to_tensor(matrix, name="matrix")

            dtype = self._matrix.dtype
            if dtype not in allowed_dtypes:
                raise TypeError(
                    "Argument matrix must have dtype in %s.  Found: %s" %
                    (allowed_dtypes, dtype))

            # Special treatment for (real) Symmetric Positive Definite.
            self._is_spd = ((not dtype.is_complex) and is_self_adjoint
                            and is_positive_definite)
            if self._is_spd:
                self._chol = linalg_ops.cholesky(self._matrix)

            super(LinearOperatorMatrix,
                  self).__init__(dtype=self._matrix.dtype,
                                 graph_parents=[self._matrix],
                                 is_non_singular=is_non_singular,
                                 is_self_adjoint=is_self_adjoint,
                                 is_positive_definite=is_positive_definite,
                                 name=name)
Example #30
0
  def __init__(self,
               df,
               scale,
               cholesky_input_output_matrices=False,
               validate_args=False,
               allow_nan_stats=True,
               name="WishartFull"):
    """Construct Wishart distributions.

    Args:
      df: `float` or `double` `Tensor`. Degrees of freedom, must be greater than
        or equal to dimension of the scale matrix.
      scale: `float` or `double` `Tensor`. The symmetric positive definite
        scale matrix of the distribution.
      cholesky_input_output_matrices: Python `bool`. Any function which whose
        input or output is a matrix assumes the input is Cholesky and returns a
        Cholesky factored matrix. Example `log_prob` input takes a Cholesky and
        `sample_n` returns a Cholesky when
        `cholesky_input_output_matrices=True`.
      validate_args: Python `bool`, default `False`. When `True` distribution
        parameters are checked for validity despite possibly degrading runtime
        performance. When `False` invalid inputs may silently render incorrect
        outputs.
      allow_nan_stats: Python `bool`, default `True`. When `True`, statistics
        (e.g., mean, mode, variance) use the value "`NaN`" to indicate the
        result is undefined. When `False`, an exception is raised if one or
        more of the statistic's batch members are undefined.
      name: Python `str` name prefixed to Ops created by this class.
    """
    parameters = dict(locals())
    with ops.name_scope(name) as name:
      with ops.name_scope("init", values=[scale]):
        scale = ops.convert_to_tensor(scale)
        if validate_args:
          scale = distribution_util.assert_symmetric(scale)
        chol = linalg_ops.cholesky(scale)
        chol = control_flow_ops.with_dependencies([
            check_ops.assert_positive(array_ops.matrix_diag_part(chol))
        ] if validate_args else [], chol)
    super(WishartFull, self).__init__(
        df=df,
        scale_operator=linalg.LinearOperatorLowerTriangular(
            tril=chol,
            is_non_singular=True,
            is_positive_definite=True,
            is_square=True),
        cholesky_input_output_matrices=cholesky_input_output_matrices,
        validate_args=validate_args,
        allow_nan_stats=allow_nan_stats,
        name=name)
    self._parameters = parameters
Example #31
0
    def runFiniteDifferences(self,
                             shapes,
                             dtypes=(dtypes_lib.float32, dtypes_lib.float64,
                                     dtypes_lib.complex64,
                                     dtypes_lib.complex128),
                             scalarTest=False):
        # rocBLAS on ROCm stack does not support complex<float> GEMV yet
        with self.session(use_gpu=True and not test.is_built_with_rocm()):
            for shape in shapes:
                for batch in False, True:
                    for dtype in dtypes:
                        if not scalarTest:
                            data = np.random.randn(shape[0], shape[1])
                            if dtype.is_complex:
                                data = data.astype(np.complex64)
                                data += 1j * np.random.randn(
                                    shape[0], shape[1])
                            x = constant_op.constant(data, dtype)
                            tensor = math_ops.matmul(
                                x, math_ops.conj(
                                    array_ops.transpose(x))) / shape[0]
                        else:
                            # This is designed to be a faster test for larger matrices.
                            data = np.random.randn()
                            if dtype.is_complex:
                                data = np.complex64(data)
                                data += 1j * np.random.randn()
                            x = constant_op.constant(data, dtype)
                            R = constant_op.constant(
                                np.random.randn(shape[0], shape[1]), dtype)
                            e = math_ops.multiply(R, x)
                            tensor = math_ops.matmul(
                                e, math_ops.conj(
                                    array_ops.transpose(e))) / shape[0]

                        # Inner-most matrices in tensor are positive definite.
                        if batch:
                            tensor = array_ops.tile(
                                array_ops.expand_dims(tensor, 0), [4, 1, 1])
                        y = linalg_ops.cholesky(tensor)
                        if scalarTest:
                            y = math_ops.reduce_mean(y)
                        error = gradient_checker.compute_gradient_error(
                            x, x._shape_as_list(), y, y._shape_as_list())
                        tf_logging.info("error = %f", error)
                        if dtype == dtypes_lib.float64:
                            self.assertLess(error, 1e-5)
                        elif dtype == dtypes_lib.complex128:
                            self.assertLess(error, 5e-5)
                        else:
                            self.assertLess(error, 5e-3)
  def __init__(self,
               matrix,
               is_non_singular=None,
               is_self_adjoint=None,
               is_positive_definite=None,
               name="LinearOperatorMatrix"):
    """Initialize a `LinearOperatorMatrix`.

    Args:
      matrix:  Shape `[B1,...,Bb, M, N]` with `b >= 0`, `M, N >= 0`.
        Allowed dtypes: `float32`, `float64`, `complex64`, `complex128`.
      is_non_singular:  Expect that this operator is non-singular.
      is_self_adjoint:  Expect that this operator is equal to its hermitian
        transpose.
      is_positive_definite:  Expect that this operator is positive definite,
        meaning the real part of all eigenvalues is positive.  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
      name: A name for this `LinearOperator`.

    Raises:
      TypeError:  If `diag.dtype` is not an allowed type.
    """

    allowed_dtypes = [
        dtypes.float32, dtypes.float64, dtypes.complex64, dtypes.complex128]

    with ops.name_scope(name, values=[matrix]):
      self._matrix = ops.convert_to_tensor(matrix, name="matrix")

      dtype = self._matrix.dtype
      if dtype not in allowed_dtypes:
        raise TypeError(
            "Argument matrix must have dtype in %s.  Found: %s"
            % (allowed_dtypes, dtype))

      # Special treatment for (real) Symmetric Positive Definite.
      self._is_spd = (
          (not dtype.is_complex) and is_self_adjoint and is_positive_definite)
      if self._is_spd:
        self._chol = linalg_ops.cholesky(self._matrix)

      super(LinearOperatorMatrix, self).__init__(
          dtype=self._matrix.dtype,
          graph_parents=[self._matrix],
          is_non_singular=is_non_singular,
          is_self_adjoint=is_self_adjoint,
          is_positive_definite=is_positive_definite,
          name=name)
Example #33
0
 def test_works_with_five_different_random_pos_def_matrices(self):
   for n in range(1, 6):
     for np_type, atol in [(np.float32, 0.05), (np.float64, 1e-5)]:
       with self.session(use_gpu=True):
         # Create 2 x n x n matrix
         array = np.array(
             [_RandomPDMatrix(n, self.rng),
              _RandomPDMatrix(n, self.rng)]).astype(np_type)
         chol = linalg_ops.cholesky(array)
         for k in range(1, 3):
           rhs = self.rng.randn(2, n, k).astype(np_type)
           x = linalg_ops.cholesky_solve(chol, rhs)
           self.assertAllClose(
               rhs, math_ops.matmul(array, x).eval(), atol=atol)
Example #34
0
 def _solve(self, rhs, adjoint=False, adjoint_arg=False):
   """Default implementation of _solve."""
   if self.is_square is False:
     raise NotImplementedError(
         "Solve is not yet implemented for non-square operators.")
   logging.warn(
       "Using (possibly slow) default implementation of solve."
       "  Requires conversion to a dense matrix and O(N^3) operations.")
   rhs = linalg.adjoint(rhs) if adjoint_arg else rhs
   if self._can_use_cholesky():
     return linear_operator_util.cholesky_solve_with_broadcast(
         linalg_ops.cholesky(self.to_dense()), rhs)
   return linear_operator_util.matrix_solve_with_broadcast(
       self.to_dense(), rhs, adjoint=adjoint)
 def test_cholesky(self):
   self._skip_if_tests_to_skip_contains("cholesky")
   for use_placeholder in self._use_placeholder_options:
     for build_info in self._operator_build_infos:
       for dtype in self._dtypes_to_test:
         with self.test_session(graph=ops.Graph()) as sess:
           sess.graph.seed = random_seed.DEFAULT_GRAPH_SEED
           operator, mat = self._operator_and_matrix(
               build_info, dtype, use_placeholder=use_placeholder,
               ensure_self_adjoint_and_pd=True)
           op_chol = operator.cholesky().to_dense()
           mat_chol = linalg_ops.cholesky(mat)
           op_chol_v, mat_chol_v = sess.run([op_chol, mat_chol])
           self.assertAC(mat_chol_v, op_chol_v)
 def test_cholesky(self):
   self._skip_if_tests_to_skip_contains("cholesky")
   for use_placeholder in self._use_placeholder_options:
     for build_info in self._operator_build_infos:
       for dtype in self._dtypes_to_test:
         with self.test_session(graph=ops.Graph()) as sess:
           sess.graph.seed = random_seed.DEFAULT_GRAPH_SEED
           operator, mat = self._operator_and_matrix(
               build_info, dtype, use_placeholder=use_placeholder,
               ensure_self_adjoint_and_pd=True)
           op_chol = operator.cholesky().to_dense()
           mat_chol = linalg_ops.cholesky(mat)
           op_chol_v, mat_chol_v = sess.run([op_chol, mat_chol])
           self.assertAC(mat_chol_v, op_chol_v)
Example #37
0
  def benchmarkCholeskyOp(self):
    for size in self.sizes:
      data = self._GenerateData(size)

      with ops.Graph().as_default(), \
          session.Session() as sess, \
          ops.device("/cpu:0"):
        l = linalg_ops.cholesky(data)
        self.run_op_benchmark(
            sess, control_flow_ops.group(l,),
            min_iters=25,
            name="cholesky_cpu_{size}".format(size=size))

      if test.is_gpu_available(True):
        with ops.Graph().as_default(), \
            session.Session() as sess, \
            ops.device("/device:GPU:0"):
          l = linalg_ops.cholesky(data)
          self.run_op_benchmark(
              sess,
              control_flow_ops.group(
                  l,),
              min_iters=25,
              name="cholesky_gpu_{size}".format(size=size))
 def _assert_positive_definite(self):
   """Default implementation of _assert_positive_definite."""
   logging.warn(
       "Using (possibly slow) default implementation of "
       "assert_positive_definite."
       "  Requires conversion to a dense matrix and O(N^3) operations.")
   # If the operator is self-adjoint, then checking that
   # Cholesky decomposition succeeds + results in positive diag is necessary
   # and sufficient.
   if self.is_self_adjoint:
     return check_ops.assert_positive(
         array_ops.matrix_diag_part(linalg_ops.cholesky(self.to_dense())),
         message="Matrix was not positive definite.")
   # We have no generic check for positive definite.
   raise NotImplementedError("assert_positive_definite is not implemented.")
Example #39
0
 def _assert_positive_definite(self):
   """Default implementation of _assert_positive_definite."""
   logging.warn(
       "Using (possibly slow) default implementation of "
       "assert_positive_definite."
       "  Requires conversion to a dense matrix and O(N^3) operations.")
   # If the operator is self-adjoint, then checking that
   # Cholesky decomposition succeeds + results in positive diag is necessary
   # and sufficient.
   if self.is_self_adjoint:
     return check_ops.assert_positive(
         array_ops.matrix_diag_part(linalg_ops.cholesky(self.to_dense())),
         message="Matrix was not positive definite.")
   # We have no generic check for positive definite.
   raise NotImplementedError("assert_positive_definite is not implemented.")
 def test_cholesky(self):
   with self.test_session(graph=ops.Graph()) as sess:
     # This test fails to pass for float32 type by a small margin if we use
     # random_seed.DEFAULT_GRAPH_SEED.  The correct fix would be relaxing the
     # test tolerance but the tolerance in this test is configured universally
     # depending on its type.  So instead of lowering tolerance for all tests
     # or special casing this, just use a seed, +2, that makes this test pass.
     sess.graph.seed = random_seed.DEFAULT_GRAPH_SEED + 2
     operator, mat = self.operator_and_matrix(
         shapes_info, dtype, use_placeholder=use_placeholder,
         ensure_self_adjoint_and_pd=True)
     op_chol = operator.cholesky().to_dense()
     mat_chol = linalg_ops.cholesky(mat)
     op_chol_v, mat_chol_v = sess.run([op_chol, mat_chol])
     self.assertAC(mat_chol_v, op_chol_v)
  def _chol_capacitance(self, batch_mode):
    """Cholesky factorization of the capacitance term."""
    # Cholesky factor for (D^{-1} + V^T M^{-1} V), which is sometimes
    # known as the "capacitance" matrix.

    # self._operator will use batch if need be. Automatically.  We cannot force
    # that here.
    # M^{-1} V
    minv_v = self._operator.solve(self._v)
    # V^T M^{-1} V
    vt_minv_v = math_ops.matmul(self._v, minv_v, adjoint_a=True)

    # D^{-1} + V^T M^{-1} V
    capacitance = self._diag_inv_operator.add_to_tensor(vt_minv_v)
    # Cholesky[D^{-1} + V^T M^{-1} V]
    return linalg_ops.cholesky(capacitance)
Example #42
0
    def _chol_capacitance(self, batch_mode):
        """Cholesky factorization of the capacitance term."""
        # Cholesky factor for (D^{-1} + V^T M^{-1} V), which is sometimes
        # known as the "capacitance" matrix.

        # self._operator will use batch if need be. Automatically.  We cannot force
        # that here.
        # M^{-1} V
        minv_v = self._operator.solve(self._v)
        # V^T M^{-1} V
        vt_minv_v = math_ops.matmul(self._v, minv_v, adjoint_a=True)

        # D^{-1} + V^T M^{-1} V
        capacitance = self._diag_inv_operator.add_to_tensor(vt_minv_v)
        # Cholesky[D^{-1} + V^T M^{-1} V]
        return linalg_ops.cholesky(capacitance)
Example #43
0
    def _solve(self, rhs, adjoint=False, adjoint_arg=False):
        if self.base_operator.is_non_singular is False:
            raise ValueError(
                "Solve not implemented unless this is a perturbation of a "
                "non-singular LinearOperator.")
        # The Woodbury formula gives:
        # https://en.wikipedia.org/wiki/Woodbury_matrix_identity
        #   (L + UDV^H)^{-1}
        #   = L^{-1} - L^{-1} U (D^{-1} + V^H L^{-1} U)^{-1} V^H L^{-1}
        #   = L^{-1} - L^{-1} U C^{-1} V^H L^{-1}
        # where C is the capacitance matrix, C := D^{-1} + V^H L^{-1} U
        # Note also that, with ^{-H} being the inverse of the adjoint,
        #   (L + UDV^H)^{-H}
        #   = L^{-H} - L^{-H} V C^{-H} U^H L^{-H}
        l = self.base_operator
        if adjoint:
            # If adjoint, U and V have flipped roles in the operator.
            v, u = self._get_uv_as_tensors()
            # Capacitance should still be computed with u=self.u and v=self.v, which
            # after the "flip" on the line above means u=v, v=u. I.e. no need to
            # "flip" in the capacitance call, since the call to
            # matrix_solve_with_broadcast below is done with the `adjoint` argument,
            # and this takes care of things.
            capacitance = self._make_capacitance(u=v, v=u)
        else:
            u, v = self._get_uv_as_tensors()
            capacitance = self._make_capacitance(u=u, v=v)

        # L^{-1} rhs
        linv_rhs = l.solve(rhs, adjoint=adjoint, adjoint_arg=adjoint_arg)
        # V^H L^{-1} rhs
        vh_linv_rhs = math_ops.matmul(v, linv_rhs, adjoint_a=True)
        # C^{-1} V^H L^{-1} rhs
        if self._use_cholesky:
            capinv_vh_linv_rhs = linalg_ops.cholesky_solve(
                linalg_ops.cholesky(capacitance), vh_linv_rhs)
        else:
            capinv_vh_linv_rhs = linear_operator_util.matrix_solve_with_broadcast(
                capacitance, vh_linv_rhs, adjoint=adjoint)
        # U C^{-1} V^H M^{-1} rhs
        u_capinv_vh_linv_rhs = math_ops.matmul(u, capinv_vh_linv_rhs)
        # L^{-1} U C^{-1} V^H L^{-1} rhs
        linv_u_capinv_vh_linv_rhs = l.solve(u_capinv_vh_linv_rhs,
                                            adjoint=adjoint)

        # L^{-1} - L^{-1} U C^{-1} V^H L^{-1}
        return linv_rhs - linv_u_capinv_vh_linv_rhs
Example #44
0
 def create_distribution(batch_size, num_components, num_features):
   cat = distributions_py.Categorical(
       logits=np.random.randn(batch_size, num_components))
   mus = [
       variables.Variable(np.random.randn(batch_size, num_features))
       for _ in range(num_components)
   ]
   sigmas = [
       variables.Variable(
           psd(np.random.rand(batch_size, num_features, num_features)))
       for _ in range(num_components)
   ]
   components = list(
       distributions_py.MultivariateNormalTriL(
           loc=mu, scale_tril=linalg_ops.cholesky(sigma))
       for (mu, sigma) in zip(mus, sigmas))
   return distributions_py.Mixture(cat, components)
Example #45
0
 def create_distribution(batch_size, num_components, num_features):
   cat = ds.Categorical(
       logits=np.random.randn(batch_size, num_components))
   mus = [
       variables.Variable(np.random.randn(batch_size, num_features))
       for _ in range(num_components)
   ]
   sigmas = [
       variables.Variable(
           psd(np.random.rand(batch_size, num_features, num_features)))
       for _ in range(num_components)
   ]
   components = list(
       ds.MultivariateNormalTriL(
           loc=mu, scale_tril=linalg_ops.cholesky(sigma))
       for (mu, sigma) in zip(mus, sigmas))
   return ds.Mixture(cat, components, use_static_graph=self.use_static_graph)
  def __init__(self,
               matrix,
               is_non_singular=None,
               is_self_adjoint=None,
               is_positive_definite=None,
               name="LinearOperatorFullMatrix"):
    r"""Initialize a `LinearOperatorFullMatrix`.

    Args:
      matrix:  Shape `[B1,...,Bb, M, N]` with `b >= 0`, `M, N >= 0`.
        Allowed dtypes: `float32`, `float64`, `complex64`, `complex128`.
      is_non_singular:  Expect that this operator is non-singular.
      is_self_adjoint:  Expect that this operator is equal to its hermitian
        transpose.
      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
      name: A name for this `LinearOperator`.

    Raises:
      TypeError:  If `diag.dtype` is not an allowed type.
    """

    with ops.name_scope(name, values=[matrix]):
      self._matrix = ops.convert_to_tensor(matrix, name="matrix")
      self._check_matrix(self._matrix)

      # Special treatment for (real) Symmetric Positive Definite.
      self._is_spd = (
          (not self._matrix.dtype.is_complex)
          and is_self_adjoint and is_positive_definite)
      if self._is_spd:
        self._chol = linalg_ops.cholesky(self._matrix)

      super(LinearOperatorFullMatrix, self).__init__(
          dtype=self._matrix.dtype,
          graph_parents=[self._matrix],
          is_non_singular=is_non_singular,
          is_self_adjoint=is_self_adjoint,
          is_positive_definite=is_positive_definite,
          name=name)
  def __init__(self,
               matrix,
               is_non_singular=None,
               is_self_adjoint=None,
               is_positive_definite=None,
               name="LinearOperatorFullMatrix"):
    r"""Initialize a `LinearOperatorFullMatrix`.

    Args:
      matrix:  Shape `[B1,...,Bb, M, N]` with `b >= 0`, `M, N >= 0`.
        Allowed dtypes: `float32`, `float64`, `complex64`, `complex128`.
      is_non_singular:  Expect that this operator is non-singular.
      is_self_adjoint:  Expect that this operator is equal to its hermitian
        transpose.
      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
      name: A name for this `LinearOperator`.

    Raises:
      TypeError:  If `diag.dtype` is not an allowed type.
    """

    with ops.name_scope(name, values=[matrix]):
      self._matrix = ops.convert_to_tensor(matrix, name="matrix")
      self._check_matrix(self._matrix)

      # Special treatment for (real) Symmetric Positive Definite.
      self._is_spd = (
          (not self._matrix.dtype.is_complex)
          and is_self_adjoint and is_positive_definite)
      if self._is_spd:
        self._chol = linalg_ops.cholesky(self._matrix)

      super(LinearOperatorFullMatrix, self).__init__(
          dtype=self._matrix.dtype,
          graph_parents=[self._matrix],
          is_non_singular=is_non_singular,
          is_self_adjoint=is_self_adjoint,
          is_positive_definite=is_positive_definite,
          name=name)
Example #48
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 = array_ops.matrix_diag_part(
                linalg_ops.cholesky(self._make_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._make_capacitance())
            log_abs_det_c = math_ops.log(math_ops.abs(det_c))
            if self.dtype.is_complex:
                log_abs_det_c = math_ops.cast(log_abs_det_c, dtype=self.dtype)

        return log_abs_det_c + log_abs_det_d + log_abs_det_l
Example #49
0
 def _define_full_covariance_probs(self, shard_id, shard):
     """Defines the full covariance probabilties per example in a class.
 Updates a matrix with dimension num_examples X num_classes.
 Args:
   shard_id: id of the current shard.
   shard: current data shard, 1 X num_examples X dimensions.
 """
     diff = shard - self._means
     cholesky = linalg_ops.cholesky(self._covs + self._min_var)
     log_det_covs = 2.0 * math_ops.reduce_sum(
         math_ops.log(array_ops.matrix_diag_part(cholesky)), 1)
     x_mu_cov = math_ops.square(
         linalg_ops.matrix_triangular_solve(cholesky,
                                            array_ops.transpose(
                                                diff, perm=[0, 2, 1]),
                                            lower=True))
     diag_m = array_ops.transpose(math_ops.reduce_sum(x_mu_cov, 1))
     self._probs[shard_id] = -0.5 * (diag_m + math_ops.to_float(
         self._dimensions) * math_ops.log(2 * np.pi) + log_det_covs)
  def _chol_capacitance(self, batch_mode):
    """Cholesky factorization of the capacitance term."""
    # Cholesky factor for (D^{-1} + V^T M^{-1} V), which is sometimes
    # known as the "capacitance" matrix.
    # We can do a Cholesky decomposition, since a priori M is a
    # positive-definite Hermitian matrix, which causes the "capacitance" to
    # also be positive-definite Hermitian, and thus have a Cholesky
    # decomposition.

    # self._operator will use batch if need be. Automatically.  We cannot force
    # that here.
    # M^{-1} V
    minv_v = self._operator.solve(self._v)
    # V^T M^{-1} V
    vt_minv_v = math_ops.matmul(self._v, minv_v, adjoint_a=True)

    # D^{-1} + V^T M^{-1} V
    capacitance = self._diag_inv_operator.add_to_tensor(vt_minv_v)
    # Cholesky[D^{-1} + V^T M^{-1} V]
    return linalg_ops.cholesky(capacitance)
    def _chol_capacitance(self, batch_mode):
        """Cholesky factorization of the capacitance term."""
        # Cholesky factor for (D^{-1} + V^T M^{-1} V), which is sometimes
        # known as the "capacitance" matrix.
        # We can do a Cholesky decomposition, since a priori M is a
        # positive-definite Hermitian matrix, which causes the "capacitance" to
        # also be positive-definite Hermitian, and thus have a Cholesky
        # decomposition.

        # self._operator will use batch if need be. Automatically.  We cannot force
        # that here.
        # M^{-1} V
        minv_v = self._operator.solve(self._v)
        # V^T M^{-1} V
        vt_minv_v = math_ops.matmul(self._v, minv_v, adjoint_a=True)

        # D^{-1} + V^T M^{-1} V
        capacitance = self._diag_inv_operator.add_to_tensor(vt_minv_v)
        # Cholesky[D^{-1} + V^T M^{-1} V]
        return linalg_ops.cholesky(capacitance)
Example #52
0
  def _define_full_covariance_probs(self, shard_id, shard):
    """Defines the full covariance probabilities per example in a class.

    Updates a matrix with dimension num_examples X num_classes.

    Args:
      shard_id: id of the current shard.
      shard: current data shard, 1 X num_examples X dimensions.
    """
    diff = shard - self._means
    cholesky = linalg_ops.cholesky(self._covs + self._min_var)
    log_det_covs = 2.0 * math_ops.reduce_sum(
        math_ops.log(array_ops.matrix_diag_part(cholesky)), 1)
    x_mu_cov = math_ops.square(
        linalg_ops.matrix_triangular_solve(
            cholesky, array_ops.transpose(
                diff, perm=[0, 2, 1]), lower=True))
    diag_m = array_ops.transpose(math_ops.reduce_sum(x_mu_cov, 1))
    self._probs[shard_id] = -0.5 * (diag_m + math_ops.to_float(self._dimensions)
                                    * math_ops.log(2 * np.pi) + log_det_covs)
Example #53
0
    def _solve(self, rhs, adjoint=False, adjoint_arg=False):
        if self.base_operator.is_non_singular is False:
            raise ValueError(
                "Solve not implemented unless this is a perturbation of a "
                "non-singular LinearOperator.")
        # The Woodbury formula gives:
        # https://en.wikipedia.org/wiki/Woodbury_matrix_identity
        #   (L + UDV^H)^{-1}
        #   = L^{-1} - L^{-1} U (D^{-1} + V^H L^{-1} U)^{-1} V^H L^{-1}
        #   = L^{-1} - L^{-1} U C^{-1} V^H L^{-1}
        # where C is the capacitance matrix, C := D^{-1} + V^H L^{-1} U
        # Note also that, with ^{-H} being the inverse of the adjoint,
        #   (L + UDV^H)^{-H}
        #   = L^{-H} - L^{-H} V C^{-H} U^H L^{-H}
        l = self.base_operator
        if adjoint:
            v = self.u
            u = self.v
        else:
            v = self.v
            u = self.u

        # L^{-1} rhs
        linv_rhs = l.solve(rhs, adjoint=adjoint, adjoint_arg=adjoint_arg)
        # V^H L^{-1} rhs
        vh_linv_rhs = math_ops.matmul(v, linv_rhs, adjoint_a=True)
        # C^{-1} V^H L^{-1} rhs
        if self._use_cholesky:
            capinv_vh_linv_rhs = linalg_ops.cholesky_solve(
                linalg_ops.cholesky(self._make_capacitance()), vh_linv_rhs)
        else:
            capinv_vh_linv_rhs = linear_operator_util.matrix_solve_with_broadcast(
                self._make_capacitance(), vh_linv_rhs, adjoint=adjoint)
        # U C^{-1} V^H M^{-1} rhs
        u_capinv_vh_linv_rhs = math_ops.matmul(u, capinv_vh_linv_rhs)
        # L^{-1} U C^{-1} V^H L^{-1} rhs
        linv_u_capinv_vh_linv_rhs = l.solve(u_capinv_vh_linv_rhs,
                                            adjoint=adjoint)

        # L^{-1} - L^{-1} U C^{-1} V^H L^{-1}
        return linv_rhs - linv_u_capinv_vh_linv_rhs
  def __init__(self, matrix, verify_pd=True, name="OperatorPDFull"):
    """Initialize an OperatorPDFull.

    Args:
      matrix:  Shape `[N1,...,Nb, k, k]` tensor with `b >= 0`, `k >= 1`.  The
        last two dimensions should be `k x k` symmetric positive definite
        matrices.
      verify_pd: Whether to check that `matrix` is symmetric positive definite.
        If `verify_pd` is `False`, correct behavior is not guaranteed.
      name:  A name to prepend to all ops created by this class.
    """
    with ops.name_scope(name):
      with ops.name_scope("init", values=[matrix]):
        matrix = ops.convert_to_tensor(matrix)
        # Check symmetric here.  Positivity will be verified by checking the
        # diagonal of the Cholesky factor inside the parent class.  The Cholesky
        # factorization linalg_ops.cholesky() does not always fail for non PSD
        # matrices, so don't rely on that.
        if verify_pd:
          matrix = distribution_util.assert_symmetric(matrix)
        chol = linalg_ops.cholesky(matrix)
        super(OperatorPDFull, self).__init__(chol, verify_pd=verify_pd)
 def _verifyCholesky(self, x):
   # Verify that LL^T == x.
   with self.test_session(use_gpu=True) as sess:
     chol = linalg_ops.cholesky(x)
     verification = math_ops.matmul(chol, chol, adjoint_b=True)
     self._verifyCholeskyBase(sess, x, chol, verification)
 def _inverse(self, y):
   return (math_ops.sqrt(y) if self._static_event_ndims == 0
           else linalg_ops.cholesky(y))
 def testWrongDimensions(self):
   tensor3 = constant_op.constant([1., 2.])
   with self.assertRaises(ValueError):
     linalg_ops.cholesky(tensor3)
   with self.assertRaises(ValueError):
     linalg_ops.cholesky(tensor3)
Example #58
0
 def _get_cached_chol(self):
   if not hasattr(self, "_cached_chol"):
     self._cached_chol = linalg_ops.cholesky(self._get_cached_dense_matrix())
   return self._cached_chol