code: def get_fldj_theoretical(
      bijector,
      x,
      event_ndims,
      inverse_event_ndims=None,
      input_to_unconstrained=None,
      output_to_unconstrained=None,
  ):
      """Numerically approximate the forward log det Jacobian of a bijector.
  
      We compute the Jacobian of the chain
      output_to_unconst_vec(bijector(inverse(input_to_unconst_vec))) so that
      we're working with a full rank matrix.  We then adjust the resulting Jacobian
      for the unconstraining bijectors.
  
      Bijectors that constrain / unconstrain their inputs/outputs may not be
      testable with this method, since the composition above may reduce the test
      to something trivial.  However, bijectors that map within constrained spaces
      should be fine.
  
      Args:
        bijector: the bijector whose Jacobian we wish to approximate
        x: the value for which we want to approximate the Jacobian. Must have rank
          at least `event_ndims`.
        event_ndims: number of dimensions in an event
        inverse_event_ndims: Integer describing the number of event dimensions for
          the bijector codomain. If None, then the value of `event_ndims` is used.
        input_to_unconstrained: bijector that maps the input to the above bijector
          to an unconstrained 1-D vector.  If unspecified, flatten the input into
          a 1-D vector according to its event_ndims.
        output_to_unconstrained: bijector that maps the output of the above bijector
          to an unconstrained 1-D vector.  If unspecified, flatten the input into
          a 1-D vector according to its event_ndims.
  
      Returns:
        fldj: A gradient-based evaluation of the log det Jacobian of
          `bijector.forward` at `x`.
      """
      if inverse_event_ndims is None:
          inverse_event_ndims = event_ndims
      if input_to_unconstrained is None:
          input_to_unconstrained = reshape_bijector.Reshape(
              event_shape_in=x.shape[
                  tensorshape_util.rank(x.shape) - event_ndims :
              ],
              event_shape_out=[-1],
          )
      if output_to_unconstrained is None:
          f_x_shape = bijector.forward_event_shape(x.shape)
          output_to_unconstrained = reshape_bijector.Reshape(
              event_shape_in=f_x_shape[
                  tensorshape_util.rank(f_x_shape)
                  - inverse_event_ndims :
              ],
              event_shape_out=[-1],
          )
  
      x = tf.convert_to_tensor(x)
      x_unconstrained = 1 * input_to_unconstrained.forward(x)
      # Collapse any batch dimensions (including scalar) to a single axis.
      batch_shape = x_unconstrained.shape[:-1]
      x_unconstrained = tf.reshape(
          x_unconstrained,
          [int(np.prod(batch_shape)), x_unconstrained.shape[-1]],
      )
  
      def f(x_unconstrained, batch_shape=batch_shape):
          # Unflatten any batch dimensions now under the tape.
          unflattened_x_unconstrained = tf.reshape(
              x_unconstrained,
              tensorshape_util.concatenate(
                  batch_shape, x_unconstrained.shape[-1:]
              ),
          )
          f_x = bijector.forward(
              input_to_unconstrained.inverse(
                  unflattened_x_unconstrained
              )
          )
          return f_x
  
      def f_unconstrained(x_unconstrained, batch_shape=batch_shape):
          f_x_unconstrained = output_to_unconstrained.forward(
              f(x_unconstrained, batch_shape=batch_shape)
          )
          # Flatten any batch dimensions to a single axis.
          return tf.reshape(
              f_x_unconstrained,
              [int(np.prod(batch_shape)), f_x_unconstrained.shape[-1]],
          )
  
      jacobian = batch_jacobian(f_unconstrained, x_unconstrained)
      jacobian = tf.reshape(
          jacobian,
          tensorshape_util.concatenate(
              batch_shape, jacobian.shape[-2:]
          ),
      )
      logging.vlog(1, "Jacobian: %s", jacobian)
  
      log_det_jacobian = (
          0.5
          * tf.linalg.slogdet(
              tf.matmul(jacobian, jacobian, adjoint_a=True)
          ).log_abs_determinant
      )
  
      input_correction = (
          input_to_unconstrained.forward_log_det_jacobian(
              x, event_ndims=event_ndims
          )
      )
      output_correction = (
          output_to_unconstrained.forward_log_det_jacobian(
              f(x_unconstrained), event_ndims=inverse_event_ndims
          )
      )
      return (
          log_det_jacobian
          + tf.cast(input_correction, log_det_jacobian.dtype)
          - tf.cast(output_correction, log_det_jacobian.dtype)
      )
  
imports: from absl import logging
  import numpy
  import tensorflow.compat.v2
  from tensorflow_probability.python.bijectors import bijector
  from tensorflow_probability.python.bijectors import reshape
  from tensorflow_probability.python.distributions import uniform
  from tensorflow_probability.python.internal import dtype_util
  from tensorflow_probability.python.internal import tensorshape_util
  from tensorflow_probability.python.internal import test_util
  from tensorflow_probability.python.math.gradient import batch_jacobian
label_desc: Use image node_id 7 for calling a global function with example usage: get_fldj_theoretical(bijector, x, event_ndims, inverse_event_ndims, input_to_unconstrained, output_to_unconstrained) and returns: unknown, f_x, tf