Exemple #1
0
  def testDiag(self):
    with self.test_session():
      shift = np.array([-1, 0, 1], dtype=np.float32)
      diag = np.array([[1, 2, 3],
                       [2, 5, 6]], dtype=np.float32)
      scale = linalg.LinearOperatorDiag(diag, is_non_singular=True)
      affine = affine_linear_operator_lib.AffineLinearOperator(
          shift=shift, scale=scale, validate_args=True)

      x = np.array([[1, 0, -1], [2, 3, 4]], dtype=np.float32)
      y = diag * x + shift
      ildj = -np.sum(np.log(np.abs(diag)), axis=-1)

      self.assertEqual(affine.name, "affine_linear_operator")
      self.assertAllClose(y, affine.forward(x).eval())
      self.assertAllClose(x, affine.inverse(y).eval())
      self.assertAllClose(ildj, affine.inverse_log_det_jacobian(y).eval())
      self.assertAllClose(-affine.inverse_log_det_jacobian(y).eval(),
                          affine.forward_log_det_jacobian(x).eval())
def make_diag_scale(loc=None,
                    scale_diag=None,
                    scale_identity_multiplier=None,
                    shape_hint=None,
                    validate_args=False,
                    assert_positive=False,
                    name=None):
    """Creates a LinOp representing a diagonal matrix.

  Args:
    loc: Floating-point `Tensor`. This is used for inferring shape in the case
      where only `scale_identity_multiplier` is set.
    scale_diag: Floating-point `Tensor` representing the diagonal matrix.
      `scale_diag` has shape [N1, N2, ...  k], which represents a k x k
      diagonal matrix.
      When `None` no diagonal term is added to the LinOp.
    scale_identity_multiplier: floating point rank 0 `Tensor` representing a
      scaling done to the identity matrix.
      When `scale_identity_multiplier = scale_diag = scale_tril = None` then
      `scale += IdentityMatrix`. Otherwise no scaled-identity-matrix is added
      to `scale`.
    shape_hint: scalar integer `Tensor` representing a hint at the dimension of
      the identity matrix when only `scale_identity_multiplier` is set.
    validate_args: Python `bool` indicating whether arguments should be
      checked for correctness.
    assert_positive: Python `bool` indicating whether LinOp should be checked
      for being positive definite.
    name: Python `str` name given to ops managed by this object.

  Returns:
    `LinearOperator` representing a lower triangular matrix.

  Raises:
    ValueError:  If only `scale_identity_multiplier` is set and `loc` and
      `shape_hint` are both None.
  """
    def _maybe_attach_assertion(x):
        if not validate_args:
            return x
        if assert_positive:
            return control_flow_ops.with_dependencies([
                check_ops.assert_positive(
                    x, message="diagonal part must be positive"),
            ], x)
        return control_flow_ops.with_dependencies([
            check_ops.assert_none_equal(
                x,
                array_ops.zeros([], x.dtype),
                message="diagonal part must be non-zero")
        ], x)

    with ops.name_scope(name,
                        "make_diag_scale",
                        values=[loc, scale_diag, scale_identity_multiplier]):
        loc = _convert_to_tensor(loc, name="loc")
        scale_diag = _convert_to_tensor(scale_diag, name="scale_diag")
        scale_identity_multiplier = _convert_to_tensor(
            scale_identity_multiplier, name="scale_identity_multiplier")

        if scale_diag is not None:
            if scale_identity_multiplier is not None:
                scale_diag += scale_identity_multiplier[..., array_ops.newaxis]
            return linalg.LinearOperatorDiag(
                diag=_maybe_attach_assertion(scale_diag),
                is_non_singular=True,
                is_self_adjoint=True,
                is_positive_definite=assert_positive)

        if loc is None and shape_hint is None:
            raise ValueError("Cannot infer `event_shape` unless `loc` or "
                             "`shape_hint` is specified.")

        if shape_hint is None:
            shape_hint = loc.shape[-1]

        if scale_identity_multiplier is None:
            return linalg.LinearOperatorIdentity(
                num_rows=shape_hint,
                dtype=loc.dtype.base_dtype,
                is_self_adjoint=True,
                is_positive_definite=True,
                assert_proper_shapes=validate_args)

        return linalg.LinearOperatorScaledIdentity(
            num_rows=shape_hint,
            multiplier=_maybe_attach_assertion(scale_identity_multiplier),
            is_non_singular=True,
            is_self_adjoint=True,
            is_positive_definite=assert_positive,
            assert_proper_shapes=validate_args)
def make_diag_scale(loc,
                    scale_diag,
                    scale_identity_multiplier,
                    validate_args,
                    assert_positive,
                    name=None):
    """Creates a LinOp from `scale_diag`, `scale_identity_multiplier` kwargs."""
    def _convert_to_tensor(x, name):
        return None if x is None else ops.convert_to_tensor(x, name=name)

    def _maybe_attach_assertion(x):
        if not validate_args:
            return x
        if assert_positive:
            return control_flow_ops.with_dependencies([
                check_ops.assert_positive(
                    x, message="diagonal part must be positive"),
            ], x)
        # TODO(b/35157376): Use `assert_none_equal` once it exists.
        return control_flow_ops.with_dependencies([
            check_ops.assert_greater(math_ops.abs(x),
                                     array_ops.zeros([], x.dtype),
                                     message="diagonal part must be non-zero"),
        ], x)

    with ops.name_scope(name,
                        "make_diag_scale",
                        values=[loc, scale_diag, scale_identity_multiplier]):
        loc = _convert_to_tensor(loc, name="loc")
        scale_diag = _convert_to_tensor(scale_diag, name="scale_diag")
        scale_identity_multiplier = _convert_to_tensor(
            scale_identity_multiplier, name="scale_identity_multiplier")

        if scale_diag is not None:
            if scale_identity_multiplier is not None:
                scale_diag += scale_identity_multiplier[..., array_ops.newaxis]
            return linalg.LinearOperatorDiag(
                diag=_maybe_attach_assertion(scale_diag),
                is_non_singular=True,
                is_self_adjoint=True,
                is_positive_definite=assert_positive)

        # TODO(b/35290280): Consider inferring shape from scale_perturb_factor.
        if loc is None:
            raise ValueError(
                "Cannot infer `event_shape` unless `loc` is specified.")

        num_rows = dimension_size(loc, -1)

        if scale_identity_multiplier is None:
            return linalg.LinearOperatorIdentity(
                num_rows=num_rows,
                dtype=loc.dtype.base_dtype,
                is_self_adjoint=True,
                is_positive_definite=True,
                assert_proper_shapes=validate_args)

        return linalg.LinearOperatorScaledIdentity(
            num_rows=num_rows,
            multiplier=_maybe_attach_assertion(scale_identity_multiplier),
            is_non_singular=True,
            is_self_adjoint=True,
            is_positive_definite=assert_positive,
            assert_proper_shapes=validate_args)