16e63cd2afb9e47a7e4f236c42786f94450be04ecJoshua V. Dillon# Copyright 2016 The TensorFlow Authors. All Rights Reserved.
26e63cd2afb9e47a7e4f236c42786f94450be04ecJoshua V. Dillon#
36e63cd2afb9e47a7e4f236c42786f94450be04ecJoshua V. Dillon# Licensed under the Apache License, Version 2.0 (the "License");
46e63cd2afb9e47a7e4f236c42786f94450be04ecJoshua V. Dillon# you may not use this file except in compliance with the License.
56e63cd2afb9e47a7e4f236c42786f94450be04ecJoshua V. Dillon# You may obtain a copy of the License at
66e63cd2afb9e47a7e4f236c42786f94450be04ecJoshua V. Dillon#
76e63cd2afb9e47a7e4f236c42786f94450be04ecJoshua V. Dillon#     http://www.apache.org/licenses/LICENSE-2.0
86e63cd2afb9e47a7e4f236c42786f94450be04ecJoshua V. Dillon#
96e63cd2afb9e47a7e4f236c42786f94450be04ecJoshua V. Dillon# Unless required by applicable law or agreed to in writing, software
106e63cd2afb9e47a7e4f236c42786f94450be04ecJoshua V. Dillon# distributed under the License is distributed on an "AS IS" BASIS,
116e63cd2afb9e47a7e4f236c42786f94450be04ecJoshua V. Dillon# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
126e63cd2afb9e47a7e4f236c42786f94450be04ecJoshua V. Dillon# See the License for the specific language governing permissions and
136e63cd2afb9e47a7e4f236c42786f94450be04ecJoshua V. Dillon# limitations under the License.
146e63cd2afb9e47a7e4f236c42786f94450be04ecJoshua V. Dillon# ==============================================================================
156e63cd2afb9e47a7e4f236c42786f94450be04ecJoshua V. Dillon"""CholeskyOuterProduct bijector."""
166e63cd2afb9e47a7e4f236c42786f94450be04ecJoshua V. Dillon
176e63cd2afb9e47a7e4f236c42786f94450be04ecJoshua V. Dillonfrom __future__ import absolute_import
186e63cd2afb9e47a7e4f236c42786f94450be04ecJoshua V. Dillonfrom __future__ import division
196e63cd2afb9e47a7e4f236c42786f94450be04ecJoshua V. Dillonfrom __future__ import print_function
206e63cd2afb9e47a7e4f236c42786f94450be04ecJoshua V. Dillon
214972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlowerimport numpy as np
226e63cd2afb9e47a7e4f236c42786f94450be04ecJoshua V. Dillon
234972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlowerfrom tensorflow.python.framework import ops
244972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlowerfrom tensorflow.python.framework import tensor_util
254972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlowerfrom tensorflow.python.ops import array_ops
264972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlowerfrom tensorflow.python.ops import check_ops
274972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlowerfrom tensorflow.python.ops import control_flow_ops
284972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlowerfrom tensorflow.python.ops import linalg_ops
294972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlowerfrom tensorflow.python.ops import math_ops
304972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlowerfrom tensorflow.python.ops.distributions import bijector
314972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlowerfrom tensorflow.python.ops.distributions import util as distribution_util
326e63cd2afb9e47a7e4f236c42786f94450be04ecJoshua V. Dillon
334972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower
344972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower__all__ = [
354972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower    "CholeskyOuterProduct",
364972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower]
374972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower
384972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower
394972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlowerclass CholeskyOuterProduct(bijector.Bijector):
404972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower  """Compute `g(X) = X @ X.T`; X is lower-triangular, positive-diagonal matrix.
414972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower
424972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower  `event_ndims` must be 0 or 2, i.e., scalar or matrix.
434972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower
444972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower  Note: the upper-triangular part of X is ignored (whether or not its zero).
454972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower
464972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower  The surjectivity of g as a map from  the set of n x n positive-diagonal
474972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower  lower-triangular matrices to the set of SPD matrices follows immediately from
484972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower  executing the Cholesky factorization algorithm on an SPD matrix A to produce a
494972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower  positive-diagonal lower-triangular matrix L such that `A = L @ L.T`.
504972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower
514972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower  To prove the injectivity of g, suppose that L_1 and L_2 are lower-triangular
524972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower  with positive diagonals and satisfy `A = L_1 @ L_1.T = L_2 @ L_2.T`. Then
534972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower    `inv(L_1) @ A @ inv(L_1).T = [inv(L_1) @ L_2] @ [inv(L_1) @ L_2].T = I`.
544972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower  Setting `L_3 := inv(L_1) @ L_2`, that L_3 is a positive-diagonal
554972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower  lower-triangular matrix follows from `inv(L_1)` being positive-diagonal
564972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower  lower-triangular (which follows from the diagonal of a triangular matrix being
574972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower  its spectrum), and that the product of two positive-diagonal lower-triangular
584972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower  matrices is another positive-diagonal lower-triangular matrix.
594972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower
604972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower  A simple inductive argument (proceding one column of L_3 at a time) shows
614972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower  that, if `I = L_3 @ L_3.T`, with L_3 being lower-triangular with positive-
624972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower  diagonal, then `L_3 = I`. Thus, `L_1 = L_2`, proving injectivity of g.
634972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower
644972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower  Examples:
654972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower
664972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower  ```python
674972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower  bijector.CholeskyOuterProduct(event_ndims=2).forward(x=[[1., 0], [2, 1]])
684972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower  # Result: [[1., 2], [2, 5]], i.e., x @ x.T
694972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower
704972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower  bijector.CholeskyOuterProduct(event_ndims=2).inverse(y=[[1., 2], [2, 5]])
714972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower  # Result: [[1., 0], [2, 1]], i.e., cholesky(y).
724972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower  ```
734972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower
744972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower  """
754972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower
764972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower  def __init__(self, event_ndims=2, validate_args=False,
774972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower               name="cholesky_outer_product"):
784972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower    """Instantiates the `CholeskyOuterProduct` bijector.
794972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower
804972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower    Args:
814972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower      event_ndims: `constant` `int32` scalar `Tensor` indicating the number of
824972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower        dimensions associated with a particular draw from the distribution. Must
834972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower        be 0 or 2.
844972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower      validate_args: Python `bool` indicating whether arguments should be
854972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower        checked for correctness.
864972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower      name: Python `str` name given to ops managed by this object.
874972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower
884972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower    Raises:
894972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower      ValueError: if event_ndims is neither 0 or 2.
904972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower    """
914972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower    self._graph_parents = []
924972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower    self._name = name
934972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower    with self._name_scope("init", values=[event_ndims]):
944972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower      event_ndims = ops.convert_to_tensor(event_ndims, name="event_ndims")
954972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower      event_ndims = tensor_util.constant_value(event_ndims)
964972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower    if event_ndims is None or event_ndims not in [0, 2]:
974972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower      raise ValueError("`event_ndims` must be a TF constant which is 0 or 2")
984972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower    self._static_event_ndims = event_ndims
994972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower    super(CholeskyOuterProduct, self).__init__(
1004972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower        event_ndims=event_ndims,
1014972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower        validate_args=validate_args,
1024972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower        name=name)
1034972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower
1044972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower  def _forward(self, x):
1054972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower    if self._static_event_ndims == 0:
1064972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower      return math_ops.square(x)
1074972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower    if self.validate_args:
1084972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower      is_matrix = check_ops.assert_rank_at_least(x, 2)
1094972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower      shape = array_ops.shape(x)
1104972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower      is_square = check_ops.assert_equal(shape[-2], shape[-1])
1114972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower      x = control_flow_ops.with_dependencies([is_matrix, is_square], x)
1124972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower    # For safety, explicitly zero-out the upper triangular part.
1134972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower    x = array_ops.matrix_band_part(x, -1, 0)
1144972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower    return math_ops.matmul(x, x, adjoint_b=True)
1154972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower
1164972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower  def _inverse(self, y):
1174972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower    return (math_ops.sqrt(y) if self._static_event_ndims == 0
1184972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower            else linalg_ops.cholesky(y))
1194972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower
1204972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower  def _inverse_log_det_jacobian(self, y):
1214972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower    return -self._forward_log_det_jacobian(x=self._inverse(y))
1224972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower
1234972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower  def _forward_log_det_jacobian(self, x):
1244972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower    # Let Y be a symmetric, positive definite matrix and write:
1254972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower    #   Y = X X.T
1264972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower    # where X is lower-triangular.
1274972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower    #
1284972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower    # Observe that,
1294972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower    #   dY[i,j]/dX[a,b]
1304972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower    #   = d/dX[a,b] { X[i,:] X[j,:] }
1314972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower    #   = sum_{d=1}^p { I[i=a] I[d=b] X[j,d] + I[j=a] I[d=b] X[i,d] }
1324972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower    #
1334972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower    # To compute the Jacobian dX/dY we must represent X,Y as vectors. Since Y is
1344972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower    # symmetric and X is lower-triangular, we need vectors of dimension:
1354972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower    #   d = p (p + 1) / 2
1364972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower    # where X, Y are p x p matrices, p > 0. We use a row-major mapping, i.e.,
1374972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower    #   k = { i (i + 1) / 2 + j   i>=j
1384972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower    #       { undef               i<j
1394972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower    # and assume zero-based indexes. When k is undef, the element is dropped.
1404972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower    # Example:
1414972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower    #           j      k
1424972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower    #        0 1 2 3  /
1434972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower    #    0 [ 0 . . . ]
1444972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower    # i  1 [ 1 2 . . ]
1454972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower    #    2 [ 3 4 5 . ]
1464972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower    #    3 [ 6 7 8 9 ]
1474972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower    # Write vec[.] to indicate transforming a matrix to vector via k(i,j). (With
1484972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower    # slight abuse: k(i,j)=undef means the element is dropped.)
1494972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower    #
1504972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower    # We now show d vec[Y] / d vec[X] is lower triangular. Assuming both are
1514972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower    # defined, observe that k(i,j) < k(a,b) iff (1) i<a or (2) i=a and j<b.
1524972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower    # In both cases dvec[Y]/dvec[X]@[k(i,j),k(a,b)] = 0 since:
1534972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower    # (1) j<=i<a thus i,j!=a.
1544972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower    # (2) i=a>j  thus i,j!=a.
1554972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower    #
1564972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower    # Since the Jacobian is lower-triangular, we need only compute the product
1574972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower    # of diagonal elements:
1584972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower    #   d vec[Y] / d vec[X] @[k(i,j), k(i,j)]
1594972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower    #   = X[j,j] + I[i=j] X[i,j]
1604972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower    #   = 2 X[j,j].
1614972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower    # Since there is a 2 X[j,j] term for every lower-triangular element of X we
1624972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower    # conclude:
1634972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower    #   |Jac(d vec[Y]/d vec[X])| = 2^p prod_{j=0}^{p-1} X[j,j]^{p-j}.
1644972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower    if self._static_event_ndims == 0:
1654972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower      if self.validate_args:
1664972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower        is_positive = check_ops.assert_positive(
1674972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower            x, message="All elements must be positive.")
1684972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower        x = control_flow_ops.with_dependencies([is_positive], x)
1694972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower      return np.log(2.) + math_ops.log(x)
1704972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower
1714972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower    diag = array_ops.matrix_diag_part(x)
1724972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower
1734972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower    # We now ensure diag is columnar. Eg, if `diag = [1, 2, 3]` then the output
1744972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower    # is `[[1], [2], [3]]` and if `diag = [[1, 2, 3], [4, 5, 6]]` then the
1754972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower    # output is unchanged.
1764972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower    diag = self._make_columnar(diag)
1774972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower
1784972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower    if self.validate_args:
1794972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower      is_matrix = check_ops.assert_rank_at_least(
1804972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower          x, 2, message="Input must be a (batch of) matrix.")
1814972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower      shape = array_ops.shape(x)
1824972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower      is_square = check_ops.assert_equal(
1834972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower          shape[-2], shape[-1],
1844972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower          message="Input must be a (batch of) square matrix.")
1854972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower      # Assuming lower-triangular means we only need check diag>0.
1864972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower      is_positive_definite = check_ops.assert_positive(
1874972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower          diag, message="Input must be positive definite.")
1884972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower      x = control_flow_ops.with_dependencies(
1894972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower          [is_matrix, is_square, is_positive_definite], x)
1904972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower
1914972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower    # Create a vector equal to: [p, p-1, ..., 2, 1].
1924972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower    if x.get_shape().ndims is None or x.get_shape()[-1].value is None:
1934972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower      p_int = array_ops.shape(x)[-1]
1944972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower      p_float = math_ops.cast(p_int, dtype=x.dtype)
1954972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower    else:
1964972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower      p_int = x.get_shape()[-1].value
1974972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower      p_float = np.array(p_int, dtype=x.dtype.as_numpy_dtype)
1984972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower    exponents = math_ops.linspace(p_float, 1., p_int)
1994972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower
2004972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower    sum_weighted_log_diag = array_ops.squeeze(
2014972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower        math_ops.matmul(math_ops.log(diag),
2024972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower                        exponents[..., array_ops.newaxis]),
2034972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower        squeeze_dims=-1)
2044972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower    fldj = p_float * np.log(2.) + sum_weighted_log_diag
2054972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower
2064972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower    return fldj
2074972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower
2084972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower  def _make_columnar(self, x):
2094972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower    """Ensures non-scalar input has at least one column.
2104972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower
2114972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower    Example:
2124972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower      If `x = [1, 2, 3]` then the output is `[[1], [2], [3]]`.
2134972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower
2144972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower      If `x = [[1, 2, 3], [4, 5, 6]]` then the output is unchanged.
2154972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower
2164972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower      If `x = 1` then the output is unchanged.
2174972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower
2184972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower    Args:
2194972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower      x: `Tensor`.
2204972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower
2214972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower    Returns:
2224972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower      columnar_x: `Tensor` with at least two dimensions.
2234972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower    """
2244972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower    if x.get_shape().ndims is not None:
2254972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower      if x.get_shape().ndims == 1:
2264972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower        x = x[array_ops.newaxis, :]
2274972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower      return x
2284972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower    shape = array_ops.shape(x)
2294972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower    maybe_expanded_shape = array_ops.concat([
2304972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower        shape[:-1],
2314972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower        distribution_util.pick_vector(
2324972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower            math_ops.equal(array_ops.rank(x), 1),
2334972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower            [1], np.array([], dtype=np.int32)),
2344972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower        shape[-1:],
2354972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower    ], 0)
2364972095bb594c238de90688f1209ae8aeb7a1312A. Unique TensorFlower    return array_ops.reshape(x, maybe_expanded_shape)
237