def Func(**arg_0):
  """Creates a value-setting interceptor.

  This function creates an interceptor that sets values of Edward2 random
  variable objects. This is useful for a range of tasks, including conditioning
  on observed data, sampling from posterior predictive distributions, and as a
  building block of inference primitives such as computing log joint
  probabilities (see examples below).

  Args:
    **model_kwargs: dict of str to Tensor. Keys are the names of random
      variables in the model to which this interceptor is being applied. Values
      are Tensors to set their value to. Variables not included in this dict
      will not be set and will maintain their existing value semantics (by
      default, a sample from the parent-conditional distribution).

  Returns:
    set_values: function that sets the value of intercepted ops.

  #### Examples

  Consider for illustration a model with latent `z` and
  observed `x`, and a corresponding trainable posterior model:

  ```python
  num_observations = 10
  def model():
    z = ed.Normal(loc=0, scale=1., name='z')  # log rate
    x = ed.Poisson(rate=tf.exp(z) * tf.ones(num_observations), name='x')
    return x

  def variational_model():
    return ed.Normal(loc=tf.Variable(0.),
                     scale=tf.nn.softplus(tf.Variable(-4.)),
                     name='z')  # for simplicity, match name of the model RV.
  ```

  We can use a value-setting interceptor to condition the model on observed
  data. This approach is slightly more cumbersome than that of partially
  evaluating the complete log-joint function, but has the potential advantage
  that it returns a new model callable, which may be used to sample downstream
  variables, passed into additional transformations, etc.

  ```python
  x_observed = np.array([6, 3, 1, 8, 7, 0, 6, 4, 7, 5])
  def observed_model():
    with ed.interception(Func(x=x_observed)):
      model()
  observed_log_joint_fn = ed.make_log_joint_fn(observed_model)

  # After fixing 'x', the observed log joint is now only a function of 'z'.
  # This enables us to define a variational lower bound,
  # `E_q[ log p(x, z) - log q(z)]`, simply by evaluating the observed and
  # variational log joints at variational samples.
  variational_log_joint_fn = ed.make_log_joint_fn(variational_model)
  with ed.tape() as variational_sample:  # Sample trace from variational model.
    variational_model()
  elbo_loss = -(observed_log_joint_fn(**variational_sample) -
                variational_log_joint_fn(**variational_sample))
  ```

  After performing inference by minimizing the variational loss, a value-setting
  interceptor enables simulation from the posterior predictive distribution:

  ```python
  with ed.tape() as posterior_samples:  # tape is a map {rv.name : rv}
    variational_model()
  with ed.interception(ed.Func(**posterior_samples)):
    x = model()
  # x is a sample from p(X | Z = z') where z' ~ q(z) (the variational model)
  ```

  As another example, using a value setter inside of `ed.tape` enables
  computing the log joint probability, by setting all variables to
  posterior values and then accumulating the log probs of those values under
  the induced parent-conditional distributions. This is one way that we could
  have implemented `ed.make_log_joint_fn`:

  ```python
  def make_log_joint_fn_demo(model):
    def log_joint_fn(**model_kwargs):
      with ed.tape() as model_tape:
        with ed.Func(**model_kwargs):
          model()

      # accumulate sum_i log p(X_i = x_i | X_{:i-1} = x_{:i-1})
      log_prob = 0.
      for rv in model_tape.values():
        log_prob += tf.reduce_sum(rv.log_prob(rv.value))

      return log_prob
    return log_joint_fn
  ```

  """
  def set_values(arg_1, *arg_2, **arg_3):
    """Sets random variable values to its aligned value."""
    arg_4 = arg_3.get("name")
    if arg_4 in arg_0:
      arg_3["value"] = arg_0[arg_4]
    return interceptable(arg_1)(*arg_2, **arg_3)
  return set_values


def Func(arg_0, arg_1):
  """Filters inputs to be compatible with function `f`'s signature.

  Args:
    f: Function according to whose input signature we filter arguments.
    src_kwargs: Keyword arguments to filter according to `f`.

  Returns:
    kwargs: Dict of key-value pairs in `src_kwargs` which exist in `f`'s
      signature.
  """
  if hasattr(arg_0, "_func"):  # functions returned by tf.make_template
    arg_0 = arg_0._func  # pylint: disable=protected-access

  try:  # getargspec was deprecated in Python 3.6
    arg_2 = inspect.getfullargspec(arg_0)
  except AttributeError:
    arg_2 = inspect.getargspec(arg_0)

  arg_3 = {k: v for k, v in six.iteritems(arg_1) if k in arg_2.args}
  return arg_3


def Func(arg_0, arg_1, arg_2, arg_3, arg_4):
  """Network block for VGG."""
  arg_5 = tfp.layers.Convolution2DFlipout(
      arg_1,
      arg_2,
      padding='same',
      arg_4=arg_4)(arg_0)
  arg_5 = tf.keras.layers.BatchNormalization()(arg_5)
  arg_5 = tf.keras.layers.Activation('relu')(arg_5)

  arg_5 = tfp.layers.Convolution2DFlipout(
      arg_1,
      arg_2,
      padding='same',
      arg_4=arg_4)(arg_5)
  arg_5 = tf.keras.layers.BatchNormalization()(arg_5)
  arg_5 = tf.keras.layers.Activation('relu')(arg_5)

  arg_5 = tf.keras.layers.MaxPooling2D(
      pool_size=(2, 2), strides=arg_3)(arg_5)
  return arg_5


def Func(arg_0,
                arg_1,
                arg_2,
                arg_3,
                arg_4,
                arg_5,
                arg_6,
                arg_7,
                arg_8,
                arg_9=1000.,
                arg_10=None):
  """Builds a tree at a given tree depth and at a given state.

  The `current` state is immediately adjacent to, but outside of,
  the subtrajectory spanned by the returned `forward` and `reverse` states.

  Args:
    value_and_gradients_fn: Python callable which takes an argument like
      `*current_state` and returns a tuple of its (possibly unnormalized)
      log-density under the target distribution and its gradient with respect to
      each state.
    current_state: List of `Tensor`s representing the current states of the
      NUTS trajectory.
    current_target_log_prob: Scalar `Tensor` representing the value of
      `target_log_prob_fn` at the `current_state`.
    current_grads_target_log_prob: List of `Tensor`s representing gradient of
      `current_target_log_prob` with respect to `current_state`. Must have same
      shape as `current_state`.
    current_momentum: List of `Tensor`s representing the momentums of
      `current_state`. Must have same shape as `current_state`.
    direction: int that is either -1 or 1. It determines whether to perform
      leapfrog integration backwards (reverse) or forward in time respectively.
    depth: non-negative int that indicates how deep of a tree to build.
      Each call to `Func` takes `2**depth` leapfrog steps.
    step_size: List of `Tensor`s representing the step sizes for the leapfrog
      integrator. Must have same shape as `current_state`.
    log_slice_sample: The log of an auxiliary slice variable. It is used
      together with `max_simulation_error` to avoid simulating trajectories with
      too much numerical error.
    max_simulation_error: Maximum simulation error to tolerate before
      terminating the trajectory. Simulation error is the
      `log_slice_sample` minus the log-joint probability at the simulated state.
    seed: Integer to seed the random number generator.

  Returns:
    reverse_state: List of `Tensor`s representing the "reverse" states of the
      NUTS trajectory. Has same shape as `current_state`.
    reverse_target_log_prob: Scalar `Tensor` representing the value of
      `target_log_prob_fn` at the `reverse_state`.
    reverse_grads_target_log_prob: List of `Tensor`s representing gradient of
      `reverse_target_log_prob` with respect to `reverse_state`. Has same shape
      as `reverse_state`.
    reverse_momentum: List of `Tensor`s representing the momentums of
      `reverse_state`. Has same shape as `reverse_state`.
    forward_state: List of `Tensor`s representing the "forward" states of the
      NUTS trajectory. Has same shape as `current_state`.
    forward_target_log_prob: Scalar `Tensor` representing the value of
      `target_log_prob_fn` at the `forward_state`.
    forward_grads_target_log_prob: List of `Tensor`s representing gradient of
      `forward_target_log_prob` with respect to `forward_state`. Has same shape
      as `forward_state`.
    forward_momentum: List of `Tensor`s representing the momentums of
      `forward_state`. Has same shape as `forward_state`.
    next_state: List of `Tensor`s representing the next states of the NUTS
      trajectory. Has same shape as `current_state`.
    next_target_log_prob: Scalar `Tensor` representing the value of
      `target_log_prob_fn` at `next_state`.
    next_grads_target_log_prob: List of `Tensor`s representing the gradient of
      `next_target_log_prob` with respect to `next_state`.
    num_states: Number of acceptable candidate states in the subtree. A state is
      acceptable if it is "in the slice", that is, if its log-joint probability
      with its momentum is greater than `log_slice_sample`.
    continue_trajectory: bool determining whether to continue the simulation
      trajectory. The trajectory is continued if no U-turns are encountered
      within the built subtree, and if the log-probability accumulation due to
      integration error does not exceed `max_simulation_error`.
  """
  if arg_6 == 0:  # base case
    # Take a leapfrog step. Terminate the tree-building if the simulation
    # error from the leapfrog integrator is too large. States discovered by
    # continuing the simulation are likely to have very low probability.
    [
        arg_11,
        arg_12,
        arg_13,
        arg_14,
    ] = _leapfrog(
        arg_0=arg_0,
        arg_1=arg_1,
        arg_3=arg_3,
        arg_4=arg_4,
        arg_7=arg_5 * arg_7)
    arg_15 = _log_joint(arg_12, arg_14)
    arg_16 = tf.cast(arg_15 > arg_8, dtype=tf.int32)
    arg_17 = (arg_15 >
                           arg_8 - arg_9)
    return [
        arg_11,
        arg_12,
        arg_13,
        arg_14,
        arg_11,
        arg_12,
        arg_13,
        arg_14,
        arg_11,
        arg_12,
        arg_13,
        arg_16,
        arg_17,
    ]

  # Build a tree at the current state.
  arg_18 = tfd.SeedStream(arg_10, "build_tree")
  [
      arg_19,
      arg_20,
      arg_21,
      arg_22,
      arg_23,
      arg_24,
      arg_25,
      arg_26,
      arg_11,
      arg_12,
      arg_13,
      arg_16,
      arg_17,
  ] = Func(arg_0=arg_0,
                  arg_1=arg_1,
                  arg_2=arg_2,
                  arg_3=arg_3,
                  arg_4=arg_4,
                  arg_5=arg_5,
                  arg_6=arg_6 - 1,
                  arg_7=arg_7,
                  arg_8=arg_8,
                  arg_10=arg_18())
  if arg_17:
    # If the just-built subtree did not terminate, build a second subtree at
    # the forward or reverse state, as appropriate.
    if arg_5 < 0:
      [
          arg_19,
          arg_20,
          arg_21,
          arg_22,
          arg_27,
          arg_27,
          arg_27,
          arg_27,
          arg_28,
          arg_29,
          arg_30,
          arg_31,
          arg_32,
      ] = Func(
          arg_0=arg_0,
          arg_1=arg_19,
          arg_2=arg_20,
          arg_3=arg_21,
          arg_4=arg_22,
          arg_5=arg_5,
          arg_6=arg_6 - 1,
          arg_7=arg_7,
          arg_8=arg_8,
          arg_10=arg_18())
    else:
      [
          arg_27,
          arg_27,
          arg_27,
          arg_27,
          arg_23,
          arg_24,
          arg_25,
          arg_26,
          arg_28,
          arg_29,
          arg_30,
          arg_31,
          arg_32,
      ] = Func(
          arg_0=arg_0,
          arg_1=arg_23,
          arg_2=arg_24,
          arg_3=arg_25,
          arg_4=arg_26,
          arg_5=arg_5,
          arg_6=arg_6 - 1,
          arg_7=arg_7,
          arg_8=arg_8,
          arg_10=arg_18())

    # Propose either `next_state` (which came from the first subtree and so is
    # nearby) or the new forward/reverse state (which came from the second
    # subtree and so is far away).
    arg_16 += arg_31
    arg_33 = _random_bernoulli(
        [],
        probs=arg_31 / arg_16,
        dtype=tf.bool,
        arg_10=arg_18())
    if arg_33:
      arg_11 = arg_28
      arg_12 = arg_29
      arg_13 = arg_30

    # Continue the NUTS trajectory if the far subtree did not terminate either,
    # and if the reverse-most and forward-most states do not exhibit a U-turn.
    arg_34 = tf.logical_and(
        _has_no_u_turn(arg_23, arg_19, arg_26),
        _has_no_u_turn(arg_23, arg_19, arg_22))
    arg_17 = arg_32 and arg_34

  return [
      arg_19,
      arg_20,
      arg_21,
      arg_22,
      arg_23,
      arg_24,
      arg_25,
      arg_26,
      arg_11,
      arg_12,
      arg_13,
      arg_16,
      arg_17,
  ]


def Func(arg_0):
  """Wraps value and gradients function to assist with None gradients."""
  @functools.wraps(arg_0)
  def func_wrapped(*arg_1, **arg_2):
    """Wrapped function which checks for None gradients."""
    arg_3, arg_4 = arg_0(*arg_1, **arg_2)
    if any(arg_5 is None for arg_5 in arg_4):
      raise ValueError("Gradient is None for a state.")
    return arg_3, arg_4
  return func_wrapped


def Func(arg_0, arg_1, arg_2):
  """If two given states and momentum do not exhibit a U-turn pattern."""
  arg_3 = sum([
      tf.reduce_sum(input_tensor=(s1 - s2) * m)
      for s1, s2, m in zip(arg_0, arg_1, arg_2)
  ])
  return arg_3 > 0


def Func(arg_0,
              arg_1,
              arg_2,
              arg_3,
              arg_4):
  """Runs one step of leapfrog integration."""
  arg_5 = [
      m + 0.5 * step * g for m, step, g in
      zip(arg_3, arg_4, arg_2)]
  arg_6 = [
      s + step * m for s, step, m in
      zip(arg_1, arg_4, arg_5)]
  arg_7, arg_8 = arg_0(
      *arg_6)
  arg_9 = [
      m + 0.5 * step * g for m, step, g in
      zip(arg_5, arg_4, arg_8)]
  return [
      arg_6,
      arg_7,
      arg_8,
      arg_9,
  ]


def Func(arg_0, arg_1):
  """Log-joint probability given a state's log-probability and momentum."""
  arg_2 = -sum(
      [tf.reduce_sum(input_tensor=0.5 * (m**2.)) for m in arg_1])
  return arg_0 + arg_2


def Func(arg_0, arg_1, arg_2=arg_3.int32, arg_5=None, arg_6=None):
  """Returns samples from a Bernoulli distribution."""
  with arg_3.compat.v1.name_scope(arg_6, "random_bernoulli", [arg_0, arg_1]):
    arg_1 = arg_3.convert_to_tensor(value=arg_1)
    arg_7 = arg_3.random.uniform(arg_0, arg_2=arg_1.dtype, arg_5=arg_5)
    return arg_3.cast(arg_3.less(arg_7, arg_1), arg_2)


def Func(arg_0, arg_1, arg_2, arg_3,
                                   arg_4):
  """Creates multivariate standard `Normal` distribution.

  Args:
    dtype: Type of parameter's event.
    shape: Python `list`-like representing the parameter's event shape.
    name: Python `str` name prepended to any created (or existing)
      `tf.Variable`s.
    trainable: Python `bool` indicating all created `tf.Variable`s should be
      added to the graph collection `GraphKeys.TRAINABLE_VARIABLES`.
    add_variable_fn: `tf.get_variable`-like `callable` used to create (or
      access existing) `tf.Variable`s.

  Returns:
    Multivariate standard `Normal` distribution.
  """
  del arg_2, arg_3, arg_4   # unused
  arg_5 = tfd.Normal(loc=tf.zeros(arg_1, arg_0), scale=arg_0.as_numpy_dtype(1))
  arg_6 = tf.size(input=arg_5.batch_shape_tensor())
  return tfd.Independent(arg_5, reinterpreted_batch_ndims=arg_6)


def Func(arg_0, arg_1):
  """Deserializes the Keras-serialized function.

  (De)serializing Python functions from/to bytecode is unsafe. Therefore we
  also use the function's type as an anonymous function ('lambda') or named
  function in the Python environment ('function'). In the latter case, this lets
  us use the Python scope to obtain the function rather than reload it from
  bytecode. (Note that both cases are brittle!)

  Keras-deserialized functions do not perform lexical scoping. Any modules that
  the function requires must be imported within the function itself.

  This serialization mimicks the implementation in `tf.keras.layers.Lambda`.

  Args:
    serial: Serialized Keras object: typically a dict, string, or bytecode.
    function_type: Python string denoting 'function' or 'lambda'.

  Returns:
    function: Function the serialized Keras object represents.

  #### Examples

  ```python
  serial, function_type = serialize_function(lambda x: x)
  function = Func(serial, function_type)
  assert function(2.3) == 2.3  # function is identity
  ```

  """
  if arg_1 == 'function':
    # Simple lookup in custom objects
    arg_2 = tf.keras.utils.deserialize_keras_object(arg_0)
  elif arg_1 == 'lambda':
    # Unsafe deserialization from bytecode
    arg_2 = generic_utils.func_load(arg_0)
  else:
    raise TypeError('Unknown function type:', arg_1)
  return arg_2


def Func(arg_0):
  """Serializes function for Keras.

  (De)serializing Python functions from/to bytecode is unsafe. Therefore we
  return the function's type as an anonymous function ('lambda') or named
  function in the Python environment ('function'). In the latter case, this lets
  us use the Python scope to obtain the function rather than reload it from
  bytecode. (Note that both cases are brittle!)

  This serialization mimicks the implementation in `tf.keras.layers.Lambda`.

  Args:
    func: Python function to serialize.

  Returns:
    (serial, function_type): Serialized object, which is a tuple of its
    bytecode (if function is anonymous) or name (if function is named), and its
    function type.
  """
  if isinstance(arg_0, types.LambdaType):
    return generic_utils.func_dump(arg_0), 'lambda'
  return arg_0.__name__, 'function'


def Func(arg_0, arg_1):
  """Broadcasts `from_structure` to `to_structure`.

  This is useful for downstream usage of `zip` or `tf.nest.map_structure`.

  If `from_structure` is a singleton, it is tiled to match the structure of
  `to_structure`. Note that the elements in `from_structure` are not copied if
  this tiling occurs.

  Args:
    to_structure: A structure.
    from_structure: A structure.

  Returns:
    new_from_structure: Same structure as `to_structure`.

  #### Example:

  ```python
  a_structure = ['a', 'b', 'c']
  b_structure = Func(a_structure, 'd')
  # -> ['d', 'd', 'd']
  c_structure = tf.nest.map_structure(
      lambda a, b: a + b, a_structure, b_structure)
  # -> ['ad', 'bd', 'cd']
  ```
  """
  arg_2 = tf.nest.flatten(arg_1)
  if len(arg_2) == 1:
    arg_1 = tf.nest.map_structure(lambda _: arg_2[0],
                                           arg_0)
  return arg_1


def Func(arg_0, arg_1=None, arg_2=None):
  """Eagerly converts struct to Tensor, recursing upon failure."""
  if arg_1 is not None or not tf.nest.is_nested(arg_0):
    return tf.convert_to_tensor(arg_0, arg_1=arg_1)

  if _maybe_convertible_to_tensor(arg_0):
    try:
      # Try converting the structure wholesale.
      return tf.convert_to_tensor(value=arg_0, arg_2=arg_2)
    except (ValueError, TypeError):
      # Unfortunately Eager/Graph mode don't agree on the error type.
      pass
  # Try converting all of its children.
  arg_3 = _get_shallow_structure(arg_0)
  return nest.map_structure_up_to(
      arg_3, lambda s: Func(s, arg_2=arg_2), arg_0)


def Func():
  """Returns `Tensor` attributes related to shape and Python builtins."""
  # Enable "Tensor semantics" for distributions.
  # See tensorflow/python/framework/ops.py `class Tensor` for details.
  arg_0 = dict()
  # Setup overloadable operators and white-listed members / properties.
  arg_0.update((arg_1, _wrap_method(tf.Tensor, arg_1))
               for arg_1 in tf.Tensor.OVERLOADABLE_OPERATORS.union({'__iter__'}))
  # Copy some members straight-through.
  arg_0.update((arg_1, getattr(tf.Tensor, arg_1))
               for arg_1 in {'__nonzero__', '__bool__', '__array_priority__'})
  return arg_0


def Func(arg_0, arg_1):
  """Creates the mixture of Gaussians prior distribution.

  Args:
    latent_size: The dimensionality of the latent representation.
    mixture_components: Number of elements of the mixture.

  Returns:
    random_prior: A `tfd.Distribution` instance representing the distribution
      over encodings in the absence of any evidence.
  """
  if arg_1 == 1:
    # See the module docstring for why we don't learn the parameters here.
    return tfd.MultivariateNormalDiag(
        arg_2=tf.zeros([arg_0]),
        scale_identity_multiplier=1.0)

  arg_2 = tf.compat.v1.get_variable(
      name="loc", shape=[arg_1, arg_0])
  arg_3 = tf.compat.v1.get_variable(
      name="raw_scale_diag", shape=[arg_1, arg_0])
  arg_4 = tf.compat.v1.get_variable(
      name="mixture_logits", shape=[arg_1])

  return tfd.MixtureSameFamily(
      components_distribution=tfd.MultivariateNormalDiag(
          arg_2=arg_2,
          scale_diag=tf.nn.softplus(arg_3)),
      mixture_distribution=tfd.Categorical(logits=arg_4),
      name="prior")


def Func(arg_0, arg_1, arg_2):
  """Helper utility to make a field of images."""
  arg_3 = tf.shape(input=arg_0)
  arg_4 = arg_3[-3]
  arg_5 = arg_3[-2]
  arg_6 = arg_3[-1]
  arg_0 = tf.reshape(arg_0, (-1, arg_4, arg_5, arg_6))
  arg_7 = tf.shape(input=arg_0)[0]
  arg_1 = tf.minimum(arg_1, arg_7)
  arg_2 = tf.minimum(arg_7 // arg_1, arg_2)
  arg_0 = arg_0[:arg_1 * arg_2]
  arg_0 = tf.reshape(arg_0, (arg_1, arg_2, arg_4, arg_5, arg_6))
  arg_0 = tf.transpose(a=arg_0, perm=[0, 2, 1, 3, 4])
  arg_0 = tf.reshape(arg_0, [1, arg_1 * arg_4, arg_2 * arg_5, arg_6])
  return arg_0


def Func(arg_0, arg_1):
  """Downloads a file."""
  arg_2 = os.path.join(arg_0, arg_1)
  if tf.io.gfile.exists(arg_2):
    return arg_2
  if not tf.io.gfile.exists(arg_0):
    tf.io.gfile.makedirs(arg_0)
  arg_3 = os.path.join(ROOT_PATH, arg_1)
  print("Downloading %s to %s" % (arg_3, arg_2))
  urllib.request.urlretrieve(arg_3, arg_2)
  return arg_2


def Func(arg_0, arg_1, arg_2):
  """Helper to validate block sizes."""
  arg_3 = arg_0.shape
  if tensorshape_util.is_fully_defined(arg_3):
    if (tensorshape_util.rank(arg_3) != 1 or
        (tensorshape_util.num_elements(arg_3) != len(arg_1))):
      raise ValueError(
          '`block_sizes` must be `None`, or a vector of the same length as '
          '`bijectors`. Got a `Tensor` with shape {} and `bijectors` of '
          'length {}'.format(arg_3, len(arg_1)))
    return arg_0
  elif arg_2:
    arg_4 = ('`block_sizes` must be `None`, or a vector of the same length '
               'as `bijectors`.')
    with tf.control_dependencies([
        assert_util.assert_equal(
            tf.size(input=arg_0), len(arg_1), arg_4=arg_4),
        assert_util.assert_equal(tf.rank(arg_0), 1)
    ]):
      return tf.identity(arg_0)
  else:
    return arg_0


def Func(arg_0, arg_1=arg_2.compat.v1.layers.dense, arg_7=None):
  """Constructs a trainable `tfd.Bernoulli` distribution.

  This function creates a Bernoulli distribution parameterized by logits.
  Using default args, this function is mathematically equivalent to:

  ```none
  Y = Bernoulli(logits=matmul(W, x) + b)

  where,
    W in R^[d, n]
    b in R^d
  ```

  #### Examples

  This function can be used as a [logistic regression](
  https://en.wikipedia.org/wiki/Logistic_regression) loss.

  ```python
  # This example fits a logistic regression loss.
  import tensorflow as tf
  import tensorflow_probability as tfp

  # Create fictitious training data.
  dtype = np.float32
  n = 3000    # number of samples
  x_size = 4  # size of single x
  def make_training_data():
    np.random.seed(142)
    x = np.random.randn(n, x_size).astype(dtype)
    w = np.random.randn(x_size).astype(dtype)
    b = np.random.randn(1).astype(dtype)
    true_logits = np.tensordot(x, w, axes=[[-1], [-1]]) + b
    noise = np.random.logistic(size=n).astype(dtype)
    y = dtype(true_logits + noise > 0.)
    return y, x
  y, x = make_training_data()

  # Build TF graph for fitting Bernoulli maximum likelihood estimator.
  Func = tfp.trainable_distributions.Func(x)
  loss = -tf.reduce_mean(Func.log_prob(y))
  train_op = tf.train.AdamOptimizer(learning_rate=2.**-5).minimize(loss)
  mse = tf.reduce_mean(tf.squared_difference(y, Func.mean()))
  init_op = tf.global_variables_initializer()

  # Run graph 1000 times.
  num_steps = 1000
  loss_ = np.zeros(num_steps)   # Style: `_` to indicate sess.run result.
  mse_ = np.zeros(num_steps)
  with tf.Session() as sess:
    sess.run(init_op)
    for it in xrange(loss_.size):
      _, loss_[it], mse_[it] = sess.run([train_op, loss, mse])
      if it % 200 == 0 or it == loss_.size - 1:
        print("iteration:{}  loss:{}  mse:{}".format(it, loss_[it], mse_[it]))

  # ==> iteration:0    loss:0.635675370693  mse:0.222526371479
  #     iteration:200  loss:0.440077394247  mse:0.143687799573
  #     iteration:400  loss:0.440077394247  mse:0.143687844276
  #     iteration:600  loss:0.440077394247  mse:0.143687844276
  #     iteration:800  loss:0.440077424049  mse:0.143687844276
  #     iteration:999  loss:0.440077424049  mse:0.143687844276
  ```

  Args:
    x: `Tensor` with floating type. Must have statically defined rank and
      statically known right-most dimension.
    layer_fn: Python `callable` which takes input `x` and `int` scalar `d` and
      returns a transformation of `x` with shape
      `tf.concat([tf.shape(x)[:-1], [1]], axis=0)`.
      Default value: `tf.layers.dense`.
    name: A `name_scope` name for operations created by this function.
      Default value: `None` (i.e., "Func").

  Returns:
    Func: An instance of `tfd.Bernoulli`.
  """
  with arg_2.compat.v1.name_scope(arg_7, 'Func', [arg_0]):
    arg_0 = arg_2.convert_to_tensor(value=arg_0, arg_7='x')
    arg_8 = arg_2.squeeze(arg_1(arg_0, 1), axis=-1)
    return tfd.Bernoulli(arg_8=arg_8)


def Func(arg_0,
           arg_1=arg_2.compat.v1.layers.dense,
           arg_7=lambda arg_0: arg_0,
           arg_8=1.,
           arg_9=None):
  """Constructs a trainable `tfd.Normal` distribution.

  This function creates a Normal distribution parameterized by loc and scale.
  Using default args, this function is mathematically equivalent to:

  ```none
  Y = Normal(loc=matmul(W, x) + b, scale=1)

  where,
    W in R^[d, n]
    b in R^d
  ```

  #### Examples

  This function can be used as a [linear regression](
  https://en.wikipedia.org/wiki/Linear_regression) loss.

  ```python
  # This example fits a linear regression loss.
  import tensorflow as tf
  import tensorflow_probability as tfp

  # Create fictitious training data.
  dtype = np.float32
  n = 3000    # number of samples
  x_size = 4  # size of single x
  def make_training_data():
    np.random.seed(142)
    x = np.random.randn(n, x_size).astype(dtype)
    w = np.random.randn(x_size).astype(dtype)
    b = np.random.randn(1).astype(dtype)
    true_mean = np.tensordot(x, w, axes=[[-1], [-1]]) + b
    noise = np.random.randn(n).astype(dtype)
    y = true_mean + noise
    return y, x
  y, x = make_training_data()

  # Build TF graph for fitting Normal maximum likelihood estimator.
  Func = tfp.trainable_distributions.Func(x)
  loss = -tf.reduce_mean(Func.log_prob(y))
  train_op = tf.train.AdamOptimizer(learning_rate=2.**-5).minimize(loss)
  mse = tf.reduce_mean(tf.squared_difference(y, Func.mean()))
  init_op = tf.global_variables_initializer()

  # Run graph 1000 times.
  num_steps = 1000
  loss_ = np.zeros(num_steps)   # Style: `_` to indicate sess.run result.
  mse_ = np.zeros(num_steps)
  with tf.Session() as sess:
    sess.run(init_op)
    for it in xrange(loss_.size):
      _, loss_[it], mse_[it] = sess.run([train_op, loss, mse])
      if it % 200 == 0 or it == loss_.size - 1:
        print("iteration:{}  loss:{}  mse:{}".format(it, loss_[it], mse_[it]))

  # ==> iteration:0    loss:6.34114170074  mse:10.8444051743
  #     iteration:200  loss:1.40146839619  mse:0.965059816837
  #     iteration:400  loss:1.40052902699  mse:0.963181257248
  #     iteration:600  loss:1.40052902699  mse:0.963181257248
  #     iteration:800  loss:1.40052902699  mse:0.963181257248
  #     iteration:999  loss:1.40052902699  mse:0.963181257248
  ```

  Args:
    x: `Tensor` with floating type. Must have statically defined rank and
      statically known right-most dimension.
    layer_fn: Python `callable` which takes input `x` and `int` scalar `d` and
      returns a transformation of `x` with shape
      `tf.concat([tf.shape(x)[:-1], [1]], axis=0)`.
      Default value: `tf.layers.dense`.
    loc_fn: Python `callable` which transforms the `loc` parameter. Takes a
      (batch of) length-`dims` vectors and returns a `Tensor` of same shape and
      `dtype`.
      Default value: `lambda x: x`.
    scale_fn: Python `callable` or `Tensor`. If a `callable` transforms the
      `scale` parameters; if `Tensor` is the `tfd.Normal` `scale` argument.
      Takes a (batch of) length-`dims` vectors and returns a `Tensor` of same
      size. (Taking a `callable` or `Tensor` is how `tf.Variable` intializers
      behave.)
      Default value: `1`.
    name: A `name_scope` name for operations created by this function.
      Default value: `None` (i.e., "Func").

  Returns:
    Func: An instance of `tfd.Normal`.
  """
  with arg_2.compat.v1.name_scope(arg_9, 'Func', [arg_0]):
    arg_0 = arg_2.convert_to_tensor(value=arg_0, arg_9='x')
    if callable(arg_8):
      arg_10 = arg_1(arg_0, 2)
      arg_11 = arg_7(arg_10[..., 0])
      arg_12 = arg_8(arg_10[..., 1])
    else:
      arg_10 = arg_2.squeeze(arg_1(arg_0, 1), axis=-1)
      arg_11 = arg_7(arg_10)
      arg_12 = arg_2.cast(arg_8, arg_11.dtype.base_dtype)
    return tfd.Normal(arg_11=arg_11, arg_12=arg_12)


def Func(arg_0,
            arg_1=arg_2.compat.v1.layers.dense,
            arg_7=lambda arg_0: arg_0,
            arg_8=None):
  """Constructs a trainable `tfd.Poisson` distribution.

  This function creates a Poisson distribution parameterized by log rate.
  Using default args, this function is mathematically equivalent to:

  ```none
  Y = Poisson(log_rate=matmul(W, x) + b)

  where,
    W in R^[d, n]
    b in R^d
  ```

  #### Examples

  This can be used as a [Poisson regression](
  https://en.wikipedia.org/wiki/Poisson_regression) loss.

  ```python
  # This example fits a Func regression loss.
  import numpy as np
  import tensorflow as tf
  import tensorflow_probability as tfp

  # Create fictitious training data.
  dtype = np.float32
  n = 3000    # number of samples
  x_size = 4  # size of single x
  def make_training_data():
    np.random.seed(142)
    x = np.random.randn(n, x_size).astype(dtype)
    w = np.random.randn(x_size).astype(dtype)
    b = np.random.randn(1).astype(dtype)
    true_log_rate = np.tensordot(x, w, axes=[[-1], [-1]]) + b
    y = np.random.Func(lam=np.exp(true_log_rate)).astype(dtype)
    return y, x
  y, x = make_training_data()

  # Build TF graph for fitting Poisson maximum likelihood estimator.
  Func = tfp.trainable_distributions.Func(x)
  loss = -tf.reduce_mean(Func.log_prob(y))
  train_op = tf.train.AdamOptimizer(learning_rate=2.**-5).minimize(loss)
  mse = tf.reduce_mean(tf.squared_difference(y, Func.mean()))
  init_op = tf.global_variables_initializer()

  # Run graph 1000 times.
  num_steps = 1000
  loss_ = np.zeros(num_steps)   # Style: `_` to indicate sess.run result.
  mse_ = np.zeros(num_steps)
  with tf.Session() as sess:
    sess.run(init_op)
    for it in xrange(loss_.size):
      _, loss_[it], mse_[it] = sess.run([train_op, loss, mse])
      if it % 200 == 0 or it == loss_.size - 1:
        print("iteration:{}  loss:{}  mse:{}".format(it, loss_[it], mse_[it]))

  # ==> iteration:0    loss:37.0814208984  mse:6359.41259766
  #     iteration:200  loss:1.42010736465  mse:40.7654914856
  #     iteration:400  loss:1.39027583599  mse:8.77660560608
  #     iteration:600  loss:1.3902695179   mse:8.78443241119
  #     iteration:800  loss:1.39026939869  mse:8.78443622589
  #     iteration:999  loss:1.39026939869  mse:8.78444766998
  ```

  Args:
    x: `Tensor` with floating type. Must have statically defined rank and
      statically known right-most dimension.
    layer_fn: Python `callable` which takes input `x` and `int` scalar `d` and
      returns a transformation of `x` with shape
      `tf.concat([tf.shape(x)[:-1], [1]], axis=0)`.
      Default value: `tf.layers.dense`.
    log_rate_fn: Python `callable` which transforms the `log_rate` parameter.
      Takes a (batch of) length-`dims` vectors and returns a `Tensor` of same
      shape and `dtype`.
      Default value: `lambda x: x`.
    name: A `name_scope` name for operations created by this function.
      Default value: `None` (i.e., "Func").

  Returns:
    Func: An instance of `tfd.Poisson`.
  """
  with arg_2.compat.v1.name_scope(arg_8, 'Func', [arg_0]):
    arg_0 = arg_2.convert_to_tensor(value=arg_0, arg_8='x')
    arg_9 = arg_7(arg_2.squeeze(arg_1(arg_0, 1), axis=-1))
    return tfd.Poisson(arg_9=arg_9)


def Func(arg_0, arg_1, arg_2,
               arg_3,
               arg_4=None):
  """Compute diffusion drift at the current location `current_state`.

  The drift of the diffusion at is computed as

  ```none
  0.5 * `step_size` * volatility_parts * `target_log_prob_fn(current_state)`
  + `step_size` * `grads_volatility`
  ```

  where `volatility_parts` = `volatility_fn(current_state)**2` and
  `grads_volatility` is a gradient of `volatility_parts` at the `current_state`.

  Args:
    step_size_parts: Python `list` of `Tensor`s representing the step size for
      Euler-Maruyama method. Must broadcast with the shape of
      `volatility_parts`.  Larger step sizes lead to faster progress, but
      too-large step sizes make rejection exponentially more likely. When
      possible, it's often helpful to match per-variable step sizes to the
      standard deviations of the target distribution in each variable.
    volatility_parts: Python `list` of `Tensor`s representing the value of
      `volatility_fn(*state_parts)`.
    grads_volatility: Python list of `Tensor`s representing the value of the
      gradient of `volatility_parts**2` wrt the state of the chain.
    grads_target_log_prob: Python list of `Tensor`s representing
      gradient of `target_log_prob_fn(*state_parts`) wrt `state_parts`. Must
      have same shape as `volatility_parts`.
    name: Python `str` name prefixed to Ops created by this function.
      Default value: `None` (i.e., 'malaFunc').

  Returns:
    drift_parts: Tensor or Python list of `Tensor`s representing the
      state(s) of the Markov chain(s) at each result step. Has same shape as
      input `current_state_parts`.
  """

  with tf.compat.v1.name_scope(arg_4, 'malaFunc', [
      arg_0, arg_1, arg_2, arg_3
  ]):

    arg_5 = []

    for arg_6, arg_7, arg_8, arg_9 in (
        zip(arg_0,
            arg_1,
            arg_2,
            arg_3)):
      arg_10 = tf.square(arg_7)
      arg_11 = 0.5 * arg_6 * (arg_10 * arg_9
                                 + arg_8)
      arg_5.append(arg_11)

    return arg_5


def Func(arg_0,
                                       arg_1,
                                       arg_2,
                                       arg_3,
                                       arg_4,
                                       arg_5,
                                       arg_6,
                                       arg_7,
                                       arg_8=None):
  r"""Helper to `kernel` which computes the log acceptance-correction.

  Computes `log_acceptance_correction` as described in `MetropolisHastings`
  class. The proposal density is normal. More specifically,

   ```none
  q(proposed_state | current_state) \sim N(current_state + current_drift,
  step_size * current_volatility**2)

  q(current_state | proposed_state) \sim N(proposed_state + proposed_drift,
  step_size * proposed_volatility**2)
  ```

  The `log_acceptance_correction` is then

  ```none
  log_acceptance_correctio = q(current_state | proposed_state)
  - q(proposed_state | current_state)
  ```

  Args:
    current_state_parts: Python `list` of `Tensor`s representing the value(s) of
      the current state of the chain.
    proposed_state_parts:  Python `list` of `Tensor`s representing the value(s)
      of the proposed state of the chain. Must broadcast with the shape of
      `current_state_parts`.
    current_volatility_parts: Python `list` of `Tensor`s representing the value
      of `volatility_fn(*current_volatility_parts)`. Must broadcast with the
      shape of `current_state_parts`.
    proposed_volatility_parts: Python `list` of `Tensor`s representing the value
      of `volatility_fn(*proposed_volatility_parts)`. Must broadcast with the
      shape of `current_state_parts`
    current_drift_parts: Python `list` of `Tensor`s representing value of the
      drift `_get_drift(*current_state_parts, ..)`. Must broadcast with the
      shape of `current_state_parts`.
    proposed_drift_parts: Python `list` of `Tensor`s representing value of the
      drift `_get_drift(*proposed_drift_parts, ..)`. Must broadcast with the
      shape of `current_state_parts`.
    step_size_parts: Python `list` of `Tensor`s representing the step size for
      Euler-Maruyama method. Must broadcast with the shape of
      `current_state_parts`.
    independent_chain_ndims: Scalar `int` `Tensor` representing the number of
      leftmost `Tensor` dimensions which index independent chains.
    name: Python `str` name prefixed to Ops created by this function.
      Default value: `None` (i.e., 'compute_log_acceptance_correction').

  Returns:
    log_acceptance_correction: `Tensor` representing the `log`
      acceptance-correction.  (See docstring for mathematical definition.)
  """

  with tf.compat.v1.name_scope(arg_8, 'compute_log_acceptance_correction', [
      arg_0, arg_1, arg_2,
      arg_3, arg_4, arg_5,
      arg_6, arg_7
  ]):

    arg_9 = []
    arg_10 = []

    for [
        arg_11,
        arg_12,
        arg_13,
        arg_14,
        arg_15,
        arg_16,
        arg_17,
    ] in zip(
        arg_0,
        arg_1,
        arg_2,
        arg_3,
        arg_4,
        arg_5,
        arg_6,
    ):
      arg_18 = tf.range(arg_7, tf.rank(arg_11))

      arg_19 = arg_12 - arg_11

      arg_13 *= tf.sqrt(arg_17)

      arg_20 = (arg_19 - arg_15) / arg_13

      arg_14 *= tf.sqrt(arg_17)
      # Compute part of `q(proposed_state | current_state)`
      arg_20 = (
          tf.reduce_sum(
              input_tensor=mcmc_util.safe_sum(
                  [tf.math.log(arg_13),
                   0.5 * (arg_20**2)]),
              arg_18=arg_18))
      arg_9.append(-arg_20)

      # Compute part of `q(current_state | proposed_state)`
      arg_21 = (arg_19 + arg_16) / arg_14
      arg_21 = (
          tf.reduce_sum(
              input_tensor=mcmc_util.safe_sum(
                  [tf.math.log(arg_14), 0.5 * (arg_21**2)]),
              arg_18=arg_18))
      arg_10.append(-arg_21)

    # Compute `q(proposed_state | current_state)`
    arg_22 = tf.reduce_sum(
        input_tensor=tf.stack(arg_9, arg_18=-1), arg_18=-1)
    # Compute `q(current_state | proposed_state)`
    arg_23 = tf.reduce_sum(
        input_tensor=tf.stack(arg_10, arg_18=-1), arg_18=-1)

    return mcmc_util.safe_sum([arg_23,
                               -arg_22])


def Func(arg_0,
                                        arg_1,
                                        arg_2=None,
                                        arg_3=None,
                                        arg_4=None,
                                        arg_5=10):
  """Helper which computes `volatility_fn` results and grads, if needed."""
  arg_6 = list(arg_1) if mcmc_util.is_list_like(arg_1) else [arg_1]
  arg_7 = arg_3 is None

  # Convert `volatility_fn_results` to a list
  if arg_2 is None:
    arg_2 = arg_0(*arg_6)

  arg_2 = (list(arg_2)
                           if mcmc_util.is_list_like(arg_2)
                           else [arg_2])
  if len(arg_2) == 1:
    arg_2 *= len(arg_6)
  if len(arg_6) != len(arg_2):
    raise ValueError('`volatility_fn` should return a tensor or a list '
                     'of the same length as `current_state`.')

  # The shape of 'volatility_parts' needs to have the number of chains as a
  # leading dimension. For determinism we broadcast 'volatility_parts' to the
  # shape of `state_parts` since each dimension of `state_parts` could have a
  # different volatility value.

  arg_2 = _maybe_broadcast_volatility(arg_2,
                                                      arg_6)
  if arg_3 is None:
    [
        arg_8,
        arg_3,
    ] = diag_jacobian(
        xs=arg_6,
        ys=arg_2,
        arg_4=arg_4,
        arg_5=arg_5,
        fn=arg_0)

  # Compute gradient of `volatility_parts**2`
  if arg_7:
    arg_3 = [
        2. * g * volatility if g is not None else tf.zeros_like(
            fn_arg, dtype=fn_arg.dtype.base_dtype)
        for g, volatility, fn_arg in zip(
            arg_3, arg_2, arg_6)
    ]

  return arg_2, arg_3


def Func(arg_0,
                                arg_1):
  """Helper to broadcast `volatility_parts` to the shape of `state_parts`."""
  return [arg_2 + tf.zeros_like(arg_3, dtype=arg_3.dtype.base_dtype)
          for arg_2, arg_3 in zip(arg_0, arg_1)]


def Func(arg_0, arg_1, arg_2, arg_3=None):
    """Calls `fn`, appropriately reshaping its input `x` and output."""
    # Note: we take `extra_kwargs` as a dict rather than `**extra_kwargs`
    # because it is possible the user provided extra kwargs would itself
    # have `fn` and/or `x` as a key.
    with tf.control_dependencies(arg_0._runtime_assertions +
                                 arg_0._validate_sample_arg(arg_2)):
      arg_4, arg_5 = arg_0._sample_shape(arg_2)
      arg_6 = tf.concat(
          [
              arg_4,
              arg_0.distribution.batch_shape_tensor(),
              arg_0.event_shape_tensor(),
          ],
          axis=0)
      arg_7 = tf.reshape(arg_2, arg_6)
      arg_8 = arg_1(arg_7, **arg_3) if arg_3 else arg_1(arg_7)
      arg_9 = tf.concat(
          [
              arg_4,
              arg_0._batch_shape_unexpanded,
          ], axis=0)
      arg_8 = tf.reshape(arg_8, arg_9)
      if (tensorshape_util.rank(arg_5) is not None and
          tensorshape_util.rank(arg_0.batch_shape) is not None):
        arg_9 = tensorshape_util.concatenate(arg_5,
                                                 arg_0.batch_shape)
        tensorshape_util.set_shape(arg_8, arg_9)
      return arg_8


def Func(
      arg_0,
      arg_1,
      arg_2=None,
      arg_3=None,
      arg_4=None):
    """Calls `fn` and appropriately reshapes its output."""
    # Note: we take `extra_kwargs` as a dict rather than `**extra_kwargs`
    # because it is possible the user provided extra kwargs would itself
    # have `fn`, `event_shape_list`, `static_event_shape_list` and/or
    # `extra_kwargs` as keys.
    with tf.control_dependencies(arg_0._runtime_assertions):
      if arg_2 is None:
        arg_2 = [arg_0._event_shape_tensor()]
      if arg_3 is None:
        arg_3 = [arg_0.event_shape]
      arg_5 = tf.concat(
          [arg_0._batch_shape_unexpanded] + arg_2, axis=0)
      arg_6 = tf.reshape(arg_1(**arg_4) if arg_4 else arg_1(),
                          arg_5)
      if (tensorshape_util.rank(arg_0.batch_shape) is not None and
          tensorshape_util.rank(arg_0.event_shape) is not None):
        arg_7 = tf.TensorShape([])
        for arg_8 in arg_3:
          arg_7 = tensorshape_util.concatenate(arg_7, arg_8)
        arg_9 = tensorshape_util.concatenate(
            arg_0.batch_shape, arg_7)
        tensorshape_util.set_shape(arg_6, arg_9)
      return arg_6


def Func(arg_0, arg_1, arg_2):
  """The binomial cumulative distribution function.

  Args:
    k: floating point `Tensor`.
    n: floating point `Tensor`.
    p: floating point `Tensor`.

  Returns:
    `sum_{j=0}^k p^j (1 - p)^(n - j)`.
  """
  # Trick for getting safe backprop/gradients into n, k when
  #   betainc(a = 0, ..) = nan
  # Write:
  #   where(unsafe, safe_output, betainc(where(unsafe, safe_input, input)))
  arg_3 = tf.ones_like(arg_1 - arg_0)
  arg_4 = tf.equal(arg_0, arg_1)
  arg_5 = tf.where(arg_4, arg_3, arg_1 - arg_0)
  arg_6 = tf.math.betainc(a=arg_5, b=arg_0 + 1, x=1 - arg_2)
  return tf.where(arg_4, arg_3, arg_6)


def Func(arg_0, arg_1=(), arg_2=None, arg_3=None):
    """Executes `model`, creating both samples and distributions."""
    arg_4 = []
    arg_5 = []
    arg_2 = seed_stream.SeedStream('JointDistributionCoroutine', arg_2)
    arg_6 = arg_0._model()
    arg_7 = 0
    arg_8 = next(arg_6)
    try:
      while True:
        arg_9 = arg_8.distribution if isinstance(arg_8, arg_0.Root) else arg_8
        arg_4.append(arg_9)
        if (arg_3 is not None and len(arg_3) > arg_7 and
            arg_3[arg_7] is not None):
          arg_2()
          arg_10 = arg_3[arg_7]
        else:
          arg_10 = arg_9.sample(
              arg_1=arg_1 if isinstance(arg_8, arg_0.Root) else (),
              arg_2=arg_2())
        arg_5.append(arg_10)
        arg_7 += 1
        arg_8 = arg_6.send(arg_10)
    except StopIteration:
      pass
    return arg_4, arg_5


def Func(arg_0, arg_1):
  """Latent Dirichlet Allocation in terms of its generative process.

  The model posits a distribution over bags of words and is parameterized by
  a concentration and the topic-word probabilities. It collapses per-word
  topic assignments.

  Args:
    concentration: A Tensor of shape [1, num_topics], which parameterizes the
      Dirichlet prior over topics.
    topics_words: A Tensor of shape [num_topics, num_words], where each row
      (topic) denotes the probability of each word being in that topic.

  Returns:
    bag_of_words: A random variable capturing a sample from the model, of shape
      [1, num_words]. It represents one generated document as a bag of words.
  """
  arg_2 = ed.Dirichlet(arg_0=arg_0, name="topics")
  arg_3 = tf.matmul(arg_2, arg_1)
  # The observations are bags of words and therefore not one-hot. However,
  # log_prob of OneHotCategorical computes the probability correctly in
  # this case.
  arg_4 = ed.OneHotCategorical(probs=arg_3, name="bag_of_words")
  return arg_4


def Func(arg_0, arg_1, arg_2, arg_3):
  """20 newsgroups as a tf.data.Dataset."""
  arg_4 = np.load(download(arg_0, FILE_TEMPLATE.format(split=arg_1)))
  # The last row is empty in both train and test.
  arg_4 = arg_4[:-1]

  # Each row is a list of word ids in the document. We first convert this to
  # sparse COO matrix (which automatically sums the repeating words). Then,
  # we convert this COO matrix to CSR format which allows for fast querying of
  # documents.
  arg_5 = arg_4.shape[0]
  arg_6 = np.array([(row_idx, column_idx)
                      for row_idx, row in enumerate(arg_4)
                      for column_idx in row])
  arg_7 = scipy.sparse.coo_matrix(
      (np.ones(arg_6.shape[0]), (arg_6[:, 0], arg_6[:, 1])),
      shape=(arg_5, arg_2),
      dtype=np.float32)
  arg_7 = arg_7.tocsr()

  arg_8 = tf.data.Dataset.range(arg_5)

  # For training, we shuffle each epoch and repeat the epochs.
  if arg_3:
    arg_8 = arg_8.shuffle(arg_5).repeat()

  # Returns a single document as a dense TensorFlow tensor. The dataset is
  # stored as a sparse matrix outside of the graph.
  def get_row_py_func(arg_9):
    def get_row_python(arg_10):
      return np.squeeze(np.array(arg_7[arg_10].todense()), axis=0)

    arg_11 = tf.compat.v1.py_func(
        get_row_python, [arg_9], tf.float32, stateful=False)
    arg_11.set_shape((arg_2,))
    return arg_11

  arg_8 = arg_8.map(get_row_py_func)
  return arg_8


def Func(arg_0):
  """Builds fake data for unit testing."""
  arg_1 = 1000
  arg_2 = [str(i) for i in range(arg_1)]

  arg_3 = np.random.randint(
      10, size=(arg_0, arg_1)).astype(np.float32)

  def train_input_fn():
    arg_4 = tf.data.Dataset.from_tensor_slices(arg_3)
    arg_4 = arg_4.batch(arg_0).repeat()
    return tf.compat.v1.data.make_one_shot_iterator(arg_4).get_next()

  def eval_input_fn():
    arg_4 = tf.data.Dataset.from_tensor_slices(arg_3)
    arg_4 = arg_4.batch(arg_0)
    return tf.compat.v1.data.make_one_shot_iterator(arg_4).get_next()

  return train_input_fn, eval_input_fn, arg_2


def Func(arg_0, arg_1):
  """Builds iterators for train and evaluation data.

  Each object is represented as a bag-of-words vector.

  Arguments:
    data_dir: Folder in which to store the data.
    batch_size: Batch size for both train and evaluation.

  Returns:
    train_input_fn: A function that returns an iterator over the training data.
    eval_input_fn: A function that returns an iterator over the evaluation data.
    vocabulary: A mapping of word's integer index to the corresponding string.
  """

  with open(download(arg_0, "vocab.pkl"), "r") as f:
    arg_2 = pickle.load(f)
  arg_3 = len(arg_2)

  arg_4 = [None] * arg_3
  for arg_5, arg_6 in arg_2.items():
    arg_4[arg_6] = arg_5

  # Build an iterator over training batches.
  def train_input_fn():
    arg_7 = newsgroups_dataset(
        arg_0, "train", arg_3, shuffle_and_repeat=True)
    # Prefetching makes training about 1.5x faster.
    arg_7 = arg_7.batch(arg_1).prefetch(32)
    return tf.compat.v1.data.make_one_shot_iterator(arg_7).get_next()

  # Build an iterator over the heldout set.
  def eval_input_fn():
    arg_7 = newsgroups_dataset(
        arg_0, "test", arg_3, shuffle_and_repeat=False)
    arg_7 = arg_7.batch(arg_1)
    return tf.compat.v1.data.make_one_shot_iterator(arg_7).get_next()

  return train_input_fn, eval_input_fn, arg_4


def Func(arg_0,
                                 arg_1,
                                 arg_2,
                                 arg_3,
                                 arg_4):
  """Add control dependencies to the commmitment loss to update the codebook.

  Args:
    vector_quantizer: An instance of the VectorQuantizer class.
    one_hot_assignments: The one-hot vectors corresponding to the matched
      codebook entry for each code in the batch.
    codes: A `float`-like `Tensor` containing the latent vectors to be compared
      to the codebook.
    commitment_loss: The commitment loss from comparing the encoder outputs to
      their neighboring codebook entries.
    decay: Decay factor for exponential moving average.

  Returns:
    commitment_loss: Commitment loss with control dependencies.
  """
  # Use an exponential moving average to update the codebook.
  arg_5 = moving_averages.assign_moving_average(
      arg_0.ema_count,
      tf.reduce_sum(input_tensor=arg_1, axis=[0, 1]),
      arg_4,
      zero_debias=False)
  arg_6 = moving_averages.assign_moving_average(
      arg_0.ema_means,
      tf.reduce_sum(
          input_tensor=tf.expand_dims(arg_2, 2) *
          tf.expand_dims(arg_1, 3),
          axis=[0, 1]),
      arg_4,
      zero_debias=False)

  # Add small value to avoid dividing by zero.
  arg_7 = arg_5 + 1e-5
  with tf.control_dependencies([arg_3]):
    arg_8 = tf.compat.v1.assign(
        arg_0.codebook,
        arg_6 / arg_7[..., tf.newaxis])
    with tf.control_dependencies([arg_8]):
      return tf.identity(arg_3)


def Func(arg_0, arg_1):
  """Helper method to save a grid of images to a PNG file.

  Args:
    x: A numpy array of shape [n_images, height, width].
    fname: The filename to write to (including extension).
  """
  arg_2 = arg_0.shape[0]
  arg_3 = figure.Figure(figsize=(arg_2, 1), frameon=False)
  arg_4 = backend_agg.FigureCanvasAgg(arg_3)
  for arg_5 in range(arg_2):
    arg_6 = arg_3.add_subplot(1, arg_2, arg_5+1)
    arg_6.imshow(arg_0[arg_5].squeeze(),
              interpolation="none",
              cmap=cm.get_cmap("binary"))
    arg_6.axis("off")
  arg_4.print_figure(arg_1, format="png")
  print("saved %s" % arg_1)


def Func(arg_0):
  """Returns a `np.dtype` based on this `dtype`."""
  arg_0 = tf.as_dtype(arg_0)
  if hasattr(arg_0, 'Func'):
    return arg_0.Func
  return arg_0


def Func(arg_0):
  """Returns whether this is a boolean data type."""
  arg_0 = tf.as_dtype(arg_0)
  if hasattr(arg_0, 'Func'):
    return arg_0.Func
  # We use `kind` because:
  # np.issubdtype(np.uint8, np.bool) == True.
  return np.dtype(arg_0).kind == 'b'


def Func(arg_0):
  """Returns whether this is a complex floating point type."""
  arg_0 = tf.as_dtype(arg_0)
  if hasattr(arg_0, 'Func'):
    return arg_0.Func
  return np.issubdtype(np.dtype(arg_0), np.complex)


def Func(arg_0):
  """Returns the string Func for this `dtype`."""
  arg_0 = tf.as_dtype(arg_0)
  if hasattr(arg_0, 'Func'):
    return arg_0.Func
  if hasattr(arg_0, '__Func__'):
    return arg_0.__Func__
  return str(arg_0)


def Func(arg_0=None, arg_1=None):
  """Validate and return float type based on `tensors` and `dtype`.

  For ops such as matrix multiplication, inputs and weights must be of the
  same float type. This function validates that all `tensors` are the same type,
  validates that type is `dtype` (if supplied), and returns the type. Type must
  be a floating point type. If neither `tensors` nor `dtype` is supplied,
  the function will return `dtypes.float32`.

  Args:
    tensors: Tensors of input values. Can include `None` elements, which will
      be ignored.
    dtype: Expected type.

  Returns:
    Validated type.

  Raises:
    ValueError: if neither `tensors` nor `dtype` is supplied, or result is not
      float, or the common type of the inputs is not a floating point type.
  """
  if arg_0:
    arg_1 = _assert_same_base_type(arg_0, arg_1)
  if not arg_1:
    arg_1 = tf.float32
  elif not is_floating(arg_1):
    raise ValueError('Expected floating point type, got {}.'.format(arg_1))
  return arg_1


def Func(arg_0,
                         arg_1,
                         arg_2,
                         arg_3,
                         arg_4):
  """Creates the condition function pair for a reflection to be accepted."""
  def _replace_worst_with_reflected():
    arg_5 = _replace_at_index(arg_0, arg_2, arg_3)
    arg_6 = _replace_at_index(arg_1, arg_2,
                                              arg_4)
    return False, arg_5, arg_6, 0
  return _replace_worst_with_reflected


def Func(arg_0,
                  arg_1,
                  arg_2,
                  arg_3,
                  arg_4,
                  arg_5,
                  arg_6,
                  arg_7):
  """Creates the condition function pair for an expansion."""
  def _expand_and_maybe_replace():
    """Performs the expansion step."""
    arg_8 = arg_6 + arg_7 * (arg_4 - arg_6)
    arg_9 = arg_0(arg_8)
    arg_10 = (arg_9 <
                          arg_5)
    arg_11 = lambda: (arg_8, arg_9)
    arg_12 = lambda: (arg_4, arg_5)
    arg_13, arg_14 = prefer_static.cond(
        arg_10, arg_11, arg_12)
    arg_15 = _replace_at_index(arg_1, arg_3, arg_13)
    arg_16 = _replace_at_index(arg_2,
                                                  arg_3,
                                                  arg_14)
    return False, arg_15, arg_16, 1
  return _expand_and_maybe_replace


def Func(arg_0,
                            arg_1,
                            arg_2,
                            arg_3,
                            arg_4,
                            arg_5,
                            arg_6,
                            arg_7,
                            arg_8,
                            arg_9,
                            arg_10):
  """Creates the condition function pair for an outside contraction."""
  def _contraction():
    """Performs a contraction."""
    arg_11 = arg_3 + arg_8 * (arg_6 - arg_3)
    arg_12 = arg_0(arg_11)
    arg_13 = arg_12 <= arg_7
    def _accept_contraction():
      arg_14 = _replace_at_index(arg_1, arg_5, arg_11)
      arg_15 = _replace_at_index(
          arg_2,
          arg_5,
          arg_12)
      return (False,
              arg_14,
              arg_15,
              1)

    def _reject_contraction():
      return _shrink_towards_best(arg_0,
                                  arg_1,
                                  arg_4,
                                  arg_9,
                                  arg_10)

    return prefer_static.cond(arg_13,
                              _accept_contraction,
                              _reject_contraction)
  return _contraction


def Func(arg_0,
                       arg_1,
                       arg_2,
                       arg_3,
                       arg_4,
                       arg_5):
  """Returns True if the simplex has converged.

  If the simplex size is smaller than the `position_tolerance` or the variation
  of the function value over the vertices of the simplex is smaller than the
  `func_tolerance` return True else False.

  Args:
    simplex: `Tensor` of real dtype. The simplex to test for convergence. For
      more details, see the docstring for `initial_simplex` argument
      of `minimize`.
    best_vertex: `Tensor` of real dtype and rank one less than `simplex`. The
      vertex with the best (i.e. smallest) objective value.
    best_objective: Scalar `Tensor` of real dtype. The best (i.e. smallest)
      value of the objective function at a vertex.
    worst_objective: Scalar `Tensor` of same dtype as `best_objective`. The
      worst (i.e. largest) value of the objective function at a vertex.
    func_tolerance: Scalar positive `Tensor`. The tolerance for the variation
      of the objective function value over the simplex. If the variation over
      the simplex vertices is below this threshold, convergence is True.
    position_tolerance: Scalar positive `Tensor`. The algorithm stops if the
      lengths (under the supremum norm) of edges connecting to the best vertex
      are below this threshold.

  Returns:
    has_converged: A scalar boolean `Tensor` indicating whether the algorithm
      is deemed to have converged.
  """
  arg_6 = tf.abs(arg_3 -
                                 arg_2) < arg_4
  arg_7 = tf.reduce_max(
      input_tensor=tf.abs(arg_0 - arg_1)) < arg_5
  return arg_6 | arg_7


def Func(arg_0,
                  arg_1,
                  arg_2,
                  arg_3,
                  arg_4,
                  arg_5,
                  arg_6):
  """Computes the initial simplex and the objective values at the simplex.

  Args:
    objective_function:  A Python callable that accepts a point as a
      real `Tensor` and returns a `Tensor` of real dtype containing
      the value of the function at that point. The function
      to be evaluated at the simplex. If `batch_evaluate_objective` is `True`,
      the callable may be evaluated on a `Tensor` of shape `[n+1] + s `
      where `n` is the dimension of the problem and `s` is the shape of a
      single point in the domain (so `n` is the size of a `Tensor`
      representing a single point).
      In this case, the expected return value is a `Tensor` of shape `[n+1]`.
    initial_simplex: None or `Tensor` of real dtype. The initial simplex to
      start the search. If supplied, should be a `Tensor` of shape `[n+1] + s`
      where `n` is the dimension of the problem and `s` is the shape of a
      single point in the domain. Each row (i.e. the `Tensor` with a given
      value of the first index) is interpreted as a vertex of a simplex and
      hence the rows must be affinely independent. If not supplied, an axes
      aligned simplex is constructed using the `initial_vertex` and
      `step_sizes`. Only one and at least one of `initial_simplex` and
      `initial_vertex` must be supplied.
    initial_vertex: None or `Tensor` of real dtype and any shape that can
      be consumed by the `objective_function`. A single point in the domain that
      will be used to construct an axes aligned initial simplex.
    step_sizes: None or `Tensor` of real dtype and shape broadcasting
      compatible with `initial_vertex`. Supplies the simplex scale along each
      axes. Only used if `initial_simplex` is not supplied. See the docstring
      of `minimize` for more details.
    objective_at_initial_simplex: None or rank `1` `Tensor` of real dtype.
      The value of the objective function at the initial simplex.
      May be supplied only if `initial_simplex` is
      supplied. If not supplied, it will be computed.
    objective_at_initial_vertex: None or scalar `Tensor` of real dtype. The
      value of the objective function at the initial vertex. May be supplied
      only if the `initial_vertex` is also supplied.
    batch_evaluate_objective: Python `bool`. If True, the objective function
      will be evaluated on all the vertices of the simplex packed into a
      single tensor. If False, the objective will be mapped across each
      vertex separately.

  Returns:
    prepared_args: A tuple containing the following elements:
      dimension: Scalar `Tensor` of `int32` dtype. The dimension of the problem
        as inferred from the supplied arguments.
      num_vertices: Scalar `Tensor` of `int32` dtype. The number of vertices
        in the simplex.
      simplex: A `Tensor` of same dtype as `initial_simplex`
        (or `initial_vertex`). The first component of the shape of the
        `Tensor` is `num_vertices` and each element represents a vertex of
        the simplex.
      objective_at_simplex: A `Tensor` of same dtype as the dtype of the
        return value of objective_function. The shape is a vector of size
        `num_vertices`. The objective function evaluated at the simplex.
      num_evaluations: An `int32` scalar `Tensor`. The number of points on
        which the objective function was evaluated.

  Raises:
    ValueError: If any of the following conditions hold
      1. If none or more than one of `initial_simplex` and `initial_vertex` are
        supplied.
      2. If `initial_simplex` and `step_sizes` are both specified.
  """
  if arg_4 is not None and arg_1 is None:
    raise ValueError('`objective_at_initial_simplex` specified but the'
                     '`initial_simplex` was not.')

  if arg_5 is not None and arg_2 is None:
    raise ValueError('`objective_at_initial_vertex` specified but the'
                     '`initial_vertex` was not.')

  # The full simplex was specified.
  if arg_1 is not None:
    if arg_2 is not None:
      raise ValueError('Both `initial_simplex` and `initial_vertex` specified.'
                       ' Only one of the two should be specified.')

    if arg_3 is not None:
      raise ValueError('`step_sizes` must not be specified when an'
                       ' `initial_simplex` has been specified.')
    return Func_with_initial_simplex(arg_0,
                                              arg_1,
                                              arg_4,
                                              arg_6)

  if arg_2 is None:
    raise ValueError('One of `initial_simplex` or `initial_vertex`'
                     ' must be supplied')

  if arg_3 is None:
    arg_3 = _default_step_sizes(arg_2)

  return Func_with_initial_vertex(arg_0,
                                           arg_2,
                                           arg_3,
                                           arg_5,
                                           arg_6)


def Func(arg_0,
                                       arg_1,
                                       arg_2,
                                       arg_3):
  """Evaluates the objective function at the specified initial simplex."""
  arg_1 = tf.convert_to_tensor(value=arg_1)

  # If d is the dimension of the problem, the number of vertices in the
  # simplex should be d+1. From this, we can infer the number of dimensions
  # as n - 1 where n is the number of vertices specified.
  arg_4 = tf.shape(input=arg_1)[0]
  arg_5 = arg_4 - 1
  arg_6 = 0

  if arg_2 is None:
    arg_2, arg_7 = _evaluate_objective_multiple(
        arg_0, arg_1, arg_3)
    arg_6 += arg_7
  arg_2 = tf.convert_to_tensor(
      value=arg_2)
  return (arg_5,
          arg_4,
          arg_1,
          arg_2,
          arg_6)


def Func(arg_0,
                                      arg_1,
                                      arg_2,
                                      arg_3,
                                      arg_4):
  """Constructs a standard axes aligned simplex."""
  arg_5 = tf.size(input=arg_1)
  arg_6 = arg_5 + 1
  arg_7 = tf.reshape(
      tf.eye(arg_5, arg_5, dtype=arg_1.dtype.base_dtype),
      tf.concat([[arg_5], tf.shape(input=arg_1)], axis=0))

  # If step_sizes does not broadcast to initial_vertex, the multiplication
  # in the second term will fail.
  arg_8 = arg_1 + arg_2 * arg_7
  arg_9 = tf.concat([tf.expand_dims(arg_1, axis=0),
                       arg_8], axis=0)
  arg_10 = 0
  # Evaluate the objective function at the simplex vertices.
  if arg_3 is None:
    arg_3 = arg_0(arg_1)
    arg_10 += 1

  arg_11, arg_12 = _evaluate_objective_multiple(
      arg_0, arg_8, arg_4)
  arg_10 += arg_12

  arg_13 = tf.concat(
      [
          tf.expand_dims(arg_3, axis=0),
          arg_11
      ], axis=0)

  return (arg_5,
          arg_6,
          arg_9,
          arg_13,
          arg_10)


def Func(arg_0, arg_1,
                                 arg_2):
  """Evaluates the objective function on a batch of points.

  If `batch_evaluate_objective` is True, returns
  `objective function(arg_batch)` else it maps the `objective_function`
  across the `arg_batch`.

  Args:
    objective_function: A Python callable that accepts a single `Tensor` of
      rank 'R > 1' and any shape 's' and returns a scalar `Tensor` of real dtype
      containing the value of the function at that point. If
      `batch a `Tensor` of shape `[batch_size] + s ` where `batch_size` is the
      size of the batch of args. In this case, the expected return value is a
      `Tensor` of shape `[batch_size]`.
    arg_batch: A `Tensor` of real dtype. The batch of arguments at which to
      evaluate the `objective_function`. If `batch_evaluate_objective` is False,
      `arg_batch` will be unpacked along the zeroth axis and the
      `objective_function` will be applied to each element.
    batch_evaluate_objective: `bool`. Whether the `objective_function` can
      evaluate a batch of arguments at once.

  Returns:
    A tuple containing:
      objective_values: A `Tensor` of real dtype and shape `[batch_size]`.
        The value of the objective function evaluated at the supplied
        `arg_batch`.
      num_evaluations: An `int32` scalar `Tensor`containing the number of
        points on which the objective function was evaluated (i.e `batch_size`).
  """
  arg_3 = tf.shape(input=arg_1)[0]
  if arg_2:
    return arg_0(arg_1), arg_3
  return tf.map_fn(arg_0, arg_1), arg_3


def Func(arg_0, arg_1,
                            arg_2, arg_3=10, arg_4=""):
  """Save a PNG plot visualizing posterior uncertainty on heldout data.

  Args:
    input_vals: A `float`-like Numpy `array` of shape
      `[num_heldout] + IMAGE_SHAPE`, containing heldout input images.
    probs: A `float`-like Numpy array of shape `[num_monte_carlo,
      num_heldout, num_classes]` containing Monte Carlo samples of
      class probabilities for each heldout sample.
    fname: Python `str` filename to save the plot to.
    n: Python `int` number of datapoints to vizualize.
    title: Python `str` title for the plot.
  """
  arg_5 = figure.Figure(figsize=(9, 3*arg_3))
  arg_6 = backend_agg.FigureCanvasAgg(arg_5)
  for arg_7 in range(arg_3):
    arg_8 = arg_5.add_subplot(arg_3, 3, 3*arg_7 + 1)
    arg_8.imshow(arg_0[arg_7, :].reshape(IMAGE_SHAPE[:-1]), interpolation="None")

    arg_8 = arg_5.add_subplot(arg_3, 3, 3*arg_7 + 2)
    for arg_9 in arg_1:
      sns.barplot(np.arange(10), arg_9[arg_7, :], alpha=0.1, arg_8=arg_8)
      arg_8.set_ylim([0, 1])
    arg_8.set_title("posterior samples")

    arg_8 = arg_5.add_subplot(arg_3, 3, 3*arg_7 + 3)
    sns.barplot(np.arange(10), np.mean(arg_1[:, arg_7, :], axis=0), arg_8=arg_8)
    arg_8.set_ylim([0, 1])
    arg_8.set_title("predictive probs")
  arg_5.suptitle(arg_4)
  arg_5.tight_layout()

  arg_6.print_figure(arg_2, format="png")
  print("saved {}".format(arg_2))


def Func(arg_0, arg_1):
    """Instantiates an initializer from a configuration dictionary."""
    return arg_0(**{
        'initializers': [tf.compat.v2.initializers.deserialize(arg_2)
                         for arg_2 in arg_1.get('initializers', [])],
        'sizes': arg_1.get('sizes', []),
        'validate_args': arg_1.get('validate_args', False),
    })


def Func(
    arg_0, arg_1, arg_2, arg_3=None):
  """Compute the log of the exponentially weighted moving mean of the exp.

  If `log_value` is a draw from a stationary random variable, this function
  approximates `log(E[exp(log_value)])`, i.e., a weighted log-sum-exp. More
  precisely, a `tf.Variable`, `log_mean_exp_var`, is updated by `log_value`
  using the following identity:

  ```none
  log_mean_exp_var =
  = log(decay exp(log_mean_exp_var) + (1 - decay) exp(log_value))
  = log(exp(log_mean_exp_var + log(decay)) + exp(log_value + log1p(-decay)))
  = log_mean_exp_var
    + log(  exp(log_mean_exp_var   - log_mean_exp_var + log(decay))
          + exp(log_value - log_mean_exp_var + log1p(-decay)))
  = log_mean_exp_var
    + log_sum_exp([log(decay), log_value - log_mean_exp_var + log1p(-decay)]).
  ```

  In addition to numerical stability, this formulation is advantageous because
  `log_mean_exp_var` can be updated in a lock-free manner, i.e., using
  `assign_add`. (Note: the updates are not thread-safe; it's just that the
  update to the tf.Variable is presumed efficient due to being lock-free.)

  Args:
    log_mean_exp_var: `float`-like `Variable` representing the log of the
      exponentially weighted moving mean of the exp. Same shape as `log_value`.
    log_value: `float`-like `Tensor` representing a new (streaming) observation.
      Same shape as `log_mean_exp_var`.
    decay: A `float`-like `Tensor`. The moving mean decay. Typically close to
      `1.`, e.g., `0.999`.
    name: Optional name of the returned operation.

  Returns:
    log_mean_exp_var: A reference to the input 'Variable' tensor with the
      `log_value`-updated log of the exponentially weighted moving mean of exp.

  Raises:
    TypeError: if `log_mean_exp_var` does not have float type `dtype`.
    TypeError: if `log_mean_exp_var`, `log_value`, `decay` have different
      `base_dtype`.
  """
  with tf.compat.v1.name_scope(arg_3, "Func",
                               [arg_0, arg_1, arg_2]):
    # We want to update the variable in a numerically stable and lock-free way.
    # To do this, observe that variable `x` updated by `v` is:
    # x = log(w exp(x) + (1-w) exp(v))
    #   = log(exp(x + log(w)) + exp(v + log1p(-w)))
    #   = x + log(exp(x - x + log(w)) + exp(v - x + log1p(-w)))
    #   = x + lse([log(w), v - x + log1p(-w)])
    with tf.compat.v1.colocate_with(arg_0):
      arg_4 = arg_0.dtype.base_dtype
      if not arg_4.is_floating:
        raise TypeError(
            "log_mean_exp_var.base_dtype({}) does not have float type "
            "`dtype`.".format(arg_4.name))
      arg_1 = tf.convert_to_tensor(
          value=arg_1, dtype=arg_4, arg_3="log_value")
      arg_2 = tf.convert_to_tensor(value=arg_2, dtype=arg_4, arg_3="decay")
      arg_5 = (arg_1 - arg_0)[tf.newaxis, ...]
      arg_6 = tf.concat([
          tf.math.log(arg_2) * tf.ones_like(arg_5),
          arg_5 + tf.math.log1p(-arg_2)
      ],
                    axis=0)
      arg_6 = tf.reduce_logsumexp(input_tensor=arg_6, axis=0)
      return arg_0.assign_add(arg_6)


def Func(arg_0, arg_1):
    """Ensures non-scalar input has at least one column.

    Example:
      If `x = [1, 2, 3]` then the output is `[[1], [2], [3]]`.

      If `x = [[1, 2, 3], [4, 5, 6]]` then the output is unchanged.

      If `x = 1` then the output is unchanged.

    Args:
      x: `Tensor`.

    Returns:
      columnar_x: `Tensor` with at least two dimensions.
    """
    if tensorshape_util.rank(arg_1.shape) is not None:
      if tensorshape_util.rank(arg_1.shape) == 1:
        arg_1 = arg_1[tf.newaxis, :]
      return arg_1
    arg_2 = tf.shape(input=arg_1)
    arg_3 = tf.concat([
        arg_2[:-1],
        distribution_util.pick_vector(
            tf.equal(tf.rank(arg_1), 1), [1], np.array([], dtype=np.int32)),
        arg_2[-1:],
    ], 0)
    return tf.reshape(arg_1, arg_3)


def Func(arg_0, arg_1=arg_2.float32, arg_4=None, arg_5=None):
  """Generates `Tensor` consisting of `-1` or `+1`, chosen uniformly at random.

  For more details, see [Rademacher distribution](
  https://en.wikipedia.org/wiki/Rademacher_distribution).

  Args:
    shape: Vector-shaped, `int` `Tensor` representing shape of output.
    dtype: (Optional) TF `dtype` representing `dtype` of output.
    seed: (Optional) Python integer to seed the random number generator.
    name: Python `str` name prefixed to Ops created by this function.
      Default value: `None` (i.e., 'Func').

  Returns:
    rademacher: `Tensor` with specified `shape` and `dtype` consisting of `-1`
      or `+1` chosen uniformly-at-random.
  """
  with arg_2.compat.v1.name_scope(arg_5, 'Func', [arg_0, arg_4]):
    # Choose the dtype to cause `2 * random_bernoulli - 1` to run in the same
    # memory (host or device) as the downstream cast will want to put it.  The
    # convention on GPU is that int32 are in host memory and int64 are in device
    # memory.
    arg_6 = arg_2.int64 if arg_2.as_dtype(arg_1) != arg_2.int32 else arg_2.int32
    arg_7 = arg_2.random.uniform(
        arg_0, minval=0, maxval=2, arg_1=arg_6, arg_4=arg_4)
    return arg_2.cast(2 * arg_7 - 1, arg_1)


def Func(arg_0, arg_1=None, arg_2=arg_3.float32, arg_5=None, arg_6=None):
  """Generates `Tensor` of positive reals drawn from a Rayleigh distributions.

  The probability density function of a Rayleigh distribution with `scale`
  parameter is given by:

  ```none
  f(x) = x scale**-2 exp(-x**2 0.5 scale**-2)
  ```

  For more details, see [Rayleigh distribution](
  https://en.wikipedia.org/wiki/Rayleigh_distribution)

  Args:
    shape: Vector-shaped, `int` `Tensor` representing shape of output.
    scale: (Optional) Positive `float` `Tensor` representing `Rayleigh` scale.
      Default value: `None` (i.e., `scale = 1.`).
    dtype: (Optional) TF `dtype` representing `dtype` of output.
      Default value: `tf.float32`.
    seed: (Optional) Python integer to seed the random number generator.
      Default value: `None` (i.e., no seed).
    name: Python `str` name prefixed to Ops created by this function.
      Default value: `None` (i.e., 'Func').

  Returns:
    rayleigh: `Tensor` with specified `shape` and `dtype` consisting of positive
      real values drawn from a Rayleigh distribution with specified `scale`.
  """
  with arg_3.compat.v1.name_scope(arg_6, 'Func', [arg_0, arg_1, arg_5]):
    if arg_1 is not None:
      # Its important to expand the shape to match scale's, otherwise we won't
      # have independent draws.
      arg_1 = arg_3.convert_to_tensor(value=arg_1, arg_2=arg_2, arg_6='scale')
      arg_0 = arg_3.broadcast_dynamic_shape(arg_0, arg_3.shape(input=arg_1))
    arg_7 = arg_3.sqrt(-2. * arg_3.math.log(
        arg_3.random.uniform(arg_0, minval=0, maxval=1, arg_2=arg_2, arg_5=arg_5)))
    if arg_1 is None:
      return arg_7
    return arg_7 * arg_1


def Func(arg_0, arg_1, arg_2):
  """Convenience function which chooses the condition based on the predicate."""
  # Note: This function is only valid if all of pred, cond_true, and cond_false
  # are scalars. This means its semantics are arguably more like tf.cond than
  # tf.where even though we use tf.where to implement it.
  arg_3 = tf.get_static_value(tf.convert_to_tensor(value=arg_0))
  if arg_3 is None:
    return tf.where(arg_0, arg_1, arg_2)
  return arg_1 if arg_3 else arg_2


def Func(arg_0, arg_1, arg_2, arg_3, arg_4,
                                     **arg_5):
    """Finish computation of log_prob on one element of the inverse image."""
    arg_2 = arg_0._maybe_rotate_dims(arg_2, rotate_right=True)
    arg_6 = arg_0.distribution.log_prob(arg_2, **arg_5)
    if arg_0._is_maybe_event_override:
      arg_6 = tf.reduce_sum(
          input_tensor=arg_6, axis=arg_0._reduce_event_indices)
    arg_6 += tf.cast(arg_3, arg_6.dtype)
    if arg_0._is_maybe_event_override and isinstance(arg_4, int):
      tensorshape_util.set_shape(
          arg_6,
          tf.broadcast_static_shape(
              tensorshape_util.with_rank_at_least(arg_1.shape, 1)[:-arg_4],
              arg_0.batch_shape))
    return arg_6


def Func(arg_0, arg_1, arg_2=False):
    """Helper which rolls left event_dims left or right event_dims right."""
    arg_3 = tf.get_static_value(arg_0._needs_rotation)
    if arg_3 is not None and not arg_3:
      return arg_1
    arg_4 = prefer_static.rank(arg_1)
    arg_5 = (arg_4 - arg_0._rotate_ndims) if arg_2 else arg_0._rotate_ndims
    arg_6 = prefer_static.concat([
        prefer_static.range(arg_5, arg_4), prefer_static.range(0, arg_5)], axis=0)
    return tf.transpose(a=arg_1, arg_6=arg_6)


def Func(arg_0,
                              arg_1,
                              arg_2,
                              arg_3,
                              arg_4,
                              arg_5,
                              arg_6=None):
  r"""Inverse of tf.nn.batch_normalization.

  Args:
    x: Input `Tensor` of arbitrary dimensionality.
    mean: A mean `Tensor`.
    variance: A variance `Tensor`.
    offset: An offset `Tensor`, often denoted `beta` in equations, or
      None. If present, will be added to the normalized tensor.
    scale: A scale `Tensor`, often denoted `gamma` in equations, or
      `None`. If present, the scale is applied to the normalized tensor.
    variance_epsilon: A small `float` added to the minibatch `variance` to
      prevent dividing by zero.
    name: A name for this operation (optional).

  Returns:
    batch_unnormalized: The de-normalized, de-scaled, de-offset `Tensor`.
  """
  with tf.compat.v2.name_scope(arg_6 or "undo_batchnorm"):
    # inv = tf.rsqrt(variance + variance_epsilon)
    # if scale is not None:
    #   inv *= scale
    # return x * inv + (
    #     offset - mean * inv if offset is not None else -mean * inv)
    arg_7 = tf.sqrt(arg_2 + arg_5)
    if arg_4 is not None:
      arg_7 /= arg_4
    arg_8 = arg_0 * arg_7 + (
        arg_1 - arg_3 * arg_7 if arg_3 is not None else arg_1)
    return arg_8


def Func(arg_0, arg_1):
    """Check for valid BatchNormalization layer.

    Args:
      layer: Instance of `tf.layers.BatchNormalization`.
    Raises:
      ValueError: If batchnorm_layer argument is not an instance of
      `tf.layers.BatchNormalization`, or if `batchnorm_layer.renorm=True` or
      if `batchnorm_layer.virtual_batch_size` is specified.
    """
    if (not isinstance(arg_1, tf.keras.layers.BatchNormalization) and
        not isinstance(arg_1, tf.compat.v1.layers.BatchNormalization)):
      raise ValueError(
          "batchnorm_layer must be an instance of BatchNormalization layer.")
    if arg_1.renorm:
      raise ValueError("BatchNorm Bijector does not support renormalization.")
    if arg_1.virtual_batch_size:
      raise ValueError(
          "BatchNorm Bijector does not support virtual batch sizes.")


def Func(arg_0, arg_1, arg_2, arg_3):
  """Applies a single slicing step to `dist`, returning a new instance."""
  if len(arg_2) == 1 and arg_2[0] == Ellipsis:
    # The path used by Distribution.copy: batch_slice(...args..., Ellipsis)
    arg_4 = {}
  else:
    arg_4 = _slice_params_to_dict(arg_0, arg_1, arg_2)
  arg_4.update(arg_3)
  arg_5 = dict(arg_0.parameters, **arg_4)
  arg_6 = type(arg_0)(**arg_5)
  return arg_6


def Func(
    arg_0,
    arg_1,
    arg_2,
    arg_3=None,
    arg_4=None,
    arg_5=None,
    arg_6=None,
    arg_7=None,
    arg_8=None,
    arg_9=None,
    arg_10=True,
    arg_11=None,
    arg_12=None):
  """Runs multiple Fisher scoring steps.

  Args:
    model_matrix: (Batch of) `float`-like, matrix-shaped `Tensor` where each row
      represents a sample's features.
    response: (Batch of) vector-shaped `Tensor` where each element represents a
      sample's observed response (to the corresponding row of features). Must
      have same `dtype` as `model_matrix`.
    model: `tfp.glm.ExponentialFamily`-like instance which implicitly
      characterizes a negative log-likelihood loss by specifying the
      distribuion's `mean`, `gradient_mean`, and `variance`.
    model_coefficients_start: Optional (batch of) vector-shaped `Tensor`
      representing the initial model coefficients, one for each column in
      `model_matrix`. Must have same `dtype` as `model_matrix`.
      Default value: Zeros.
    predicted_linear_response_start: Optional `Tensor` with `shape`, `dtype`
      matching `response`; represents `offset` shifted initial linear
      predictions based on `model_coefficients_start`.
      Default value: `offset` if `model_coefficients is None`, and
      `tf.linalg.matvec(model_matrix, model_coefficients_start) + offset`
      otherwise.
    l2_regularizer: Optional scalar `Tensor` representing L2 regularization
      penalty, i.e.,
      `loss(w) = sum{-log p(y[i]|x[i],w) : i=1..n} + l2_regularizer ||w||_2^2`.
      Default value: `None` (i.e., no L2 regularization).
    dispersion: Optional (batch of) `Tensor` representing `response` dispersion,
      i.e., as in, `p(y|theta) := exp((y theta - A(theta)) / dispersion)`.
      Must broadcast with rows of `model_matrix`.
      Default value: `None` (i.e., "no dispersion").
    offset: Optional `Tensor` representing constant shift applied to
      `predicted_linear_response`.  Must broadcast to `response`.
      Default value: `None` (i.e., `tf.zeros_like(response)`).
    convergence_criteria_fn: Python `callable` taking:
      `is_converged_previous`, `iter_`, `model_coefficients_previous`,
      `predicted_linear_response_previous`, `model_coefficients_next`,
      `predicted_linear_response_next`, `response`, `model`, `dispersion` and
      returning a `bool` `Tensor` indicating that Fisher scoring has converged.
      See `convergence_criteria_small_relative_norm_weights_change` as an
      example function.
      Default value: `None` (i.e.,
      `convergence_criteria_small_relative_norm_weights_change`).
    learning_rate: Optional (batch of) scalar `Tensor` used to dampen iterative
      progress. Typically only needed if optimization diverges, should be no
      larger than `1` and typically very close to `1`.
      Default value: `None` (i.e., `1`).
    fast_unsafe_numerics: Optional Python `bool` indicating if faster, less
      numerically accurate methods can be employed for computing the weighted
      least-squares solution.
      Default value: `True` (i.e., "fast but possibly diminished accuracy").
    maximum_iterations: Optional maximum number of iterations of Fisher scoring
      to run; "and-ed" with result of `convergence_criteria_fn`.
      Default value: `None` (i.e., `infinity`).
    name: Python `str` used as name prefix to ops created by this function.
      Default value: `"Func"`.

  Returns:
    model_coefficients: (Batch of) vector-shaped `Tensor`; represents the
      Functed model coefficients, one for each column in `model_matrix`.
    predicted_linear_response: `response`-shaped `Tensor` representing linear
      predictions based on new `model_coefficients`, i.e.,
      `tf.linalg.matvec(model_matrix, model_coefficients) + offset`.
    is_converged: `bool` `Tensor` indicating that the returned
      `model_coefficients` met the `convergence_criteria_fn` criteria within the
      `maximum_iterations` limit.
    iter_: `int32` `Tensor` indicating the number of iterations taken.

  #### Example

  ```python
  from __future__ import print_function
  import numpy as np
  import tensorflow as tf
  import tensorflow_probability as tfp
  tfd = tfp.distributions

  def make_dataset(n, d, link, scale=1., dtype=np.float32):
    model_coefficients = tfd.Uniform(
        low=np.array(-1, dtype),
        high=np.array(1, dtype)).sample(d, seed=42)
    radius = np.sqrt(2.)
    model_coefficients *= radius / tf.linalg.norm(model_coefficients)
    model_matrix = tfd.Normal(
        loc=np.array(0, dtype),
        scale=np.array(1, dtype)).sample([n, d], seed=43)
    scale = tf.convert_to_tensor(scale, dtype)
    linear_response = tf.tensordot(
        model_matrix, model_coefficients, axes=[[1], [0]])
    if link == 'linear':
      response = tfd.Normal(loc=linear_response, scale=scale).sample(seed=44)
    elif link == 'probit':
      response = tf.cast(
          tfd.Normal(loc=linear_response, scale=scale).sample(seed=44) > 0,
          dtype)
    elif link == 'logit':
      response = tfd.Bernoulli(logits=linear_response).sample(seed=44)
    else:
      raise ValueError('unrecognized true link: {}'.format(link))
    return model_matrix, response, model_coefficients

  X, Y, w_true = make_dataset(n=int(1e6), d=100, link='probit')

  w, linear_response, is_converged, num_iter = tfp.glm.Func(
      model_matrix=X,
      response=Y,
      model=tfp.glm.BernoulliNormalCDF())
  log_likelihood = tfp.glm.BernoulliNormalCDF().log_prob(Y, linear_response)

  with tf.Session() as sess:
    [w_, linear_response_, is_converged_, num_iter_, Y_, w_true_,
     log_likelihood_] = sess.run([
        w, linear_response, is_converged, num_iter, Y, w_true,
        log_likelihood])

  print('is_converged: ', is_converged_)
  print('    num_iter: ', num_iter_)
  print('    accuracy: ', np.mean((linear_response_ > 0.) == Y_))
  print('    deviance: ', 2. * np.mean(log_likelihood_))
  print('||w0-w1||_2 / (1+||w0||_2): ', (np.linalg.norm(w_true_ - w_, ord=2) /
                                         (1. + np.linalg.norm(w_true_, ord=2))))

  # ==>
  # is_converged:  True
  #     num_iter:  6
  #     accuracy:  0.804382
  #     deviance:  -0.820746600628
  # ||w0-w1||_2 / (1+||w0||_2):  0.00619245105309
  ```

  """
  arg_13 = [arg_0, arg_1, arg_3,
                arg_4, arg_6, arg_7,
                arg_9, arg_11]
  with tf.compat.v1.name_scope(arg_12, 'Func', arg_13):
    [
        arg_0,
        arg_1,
        arg_3,
        arg_4,
        arg_7,
    ] = prepare_args(
        arg_0,
        arg_1,
        arg_3,
        arg_4,
        arg_7)
    if arg_8 is None:
      arg_8 = (
          convergence_criteria_small_relative_norm_weights_change())

    def _body(
        arg_14,
        arg_15,
        arg_16,
        arg_17):
      """`tf.while_loop` body."""
      arg_18, arg_19 = Func_one_step(
          arg_0,
          arg_1,
          arg_2,
          arg_16,
          arg_17,
          arg_5,
          arg_6,
          arg_7,
          arg_9,
          arg_10)
      arg_20 = arg_8(
          arg_14=arg_14,
          arg_15=arg_15,
          arg_16=arg_16,
          arg_17=arg_17,
          arg_18=arg_18,
          arg_19=arg_19,
          arg_1=arg_1,
          arg_2=arg_2,
          arg_6=arg_6)
      return [
          arg_20,
          arg_15 + 1,
          arg_18,
          arg_19,
      ]

    # while not converged:
    #   Func_one_step
    [
        arg_21,
        arg_15,
        arg_22,
        arg_23,
    ] = tf.while_loop(
        cond=lambda arg_21, *args: tf.logical_not(arg_21),
        body=_body,
        loop_vars=[
            tf.zeros([], np.bool),   # is_converged
            tf.zeros([], np.int32),  # iter_
            arg_3,
            arg_4,
        ],
        arg_11=arg_11)

    return [
        arg_22,
        arg_23,
        arg_21,
        arg_15
    ]


def Func(
    arg_0=1e-5,
    arg_1=2):
  """Returns Python `callable` which indicates fitting procedure has converged.

  Writing old, new `model_coefficients` as `w0`, `w1`, this function
  defines convergence as,

  ```python
  relative_euclidean_norm = (tf.norm(w0 - w1, ord=2, axis=-1) /
                             (1. + tf.norm(w0, ord=2, axis=-1)))
  reduce_all(relative_euclidean_norm < tolerance)
  ```

  where `tf.norm(x, ord=2)` denotes the [Euclidean norm](
  https://en.wikipedia.org/wiki/Norm_(mathematics)#Euclidean_norm) of `x`.

  Args:
    tolerance: `float`-like `Tensor` indicating convergence, i.e., when
      max relative Euclidean norm weights difference < tolerance`.
      Default value: `1e-5`.
    norm_order: Order of the norm. Default value: `2` (i.e., "Euclidean norm".)

  Returns:
    convergence_criteria_fn: Python `callable` which returns `bool` `Tensor`
      indicated fitting procedure has converged. (See inner function
      specification for argument signature.)
      Default value: `1e-5`.
  """
  def convergence_criteria_fn(
      arg_2,  # pylint: disable=unused-argument
      arg_3,
      arg_4,
      arg_5,  # pylint: disable=unused-argument
      arg_6,
      arg_7,  # pylint: disable=unused-argument
      arg_8,  # pylint: disable=unused-argument
      arg_9,  # pylint: disable=unused-argument
      arg_10):  # pylint: disable=unused-argument
    """Returns `bool` `Tensor` indicating if fitting procedure has converged.

    Args:
      is_converged_previous: "old" convergence results.
      iter_: Iteration number.
      model_coefficients_previous: "old" `model_coefficients`.
      predicted_linear_response_previous: "old" `predicted_linear_response`.
      model_coefficients_next: "new" `model_coefficients`.
      predicted_linear_response_next: "new: `predicted_linear_response`.
      response: (Batch of) vector-shaped `Tensor` where each element represents
        a sample's observed response (to the corresponding row of features).
        Must have same `dtype` as `model_matrix`.
      model: `tfp.glm.ExponentialFamily`-like instance used to construct the
        negative log-likelihood loss, gradient, and expected Hessian (i.e., the
        Fisher information matrix).
      dispersion: `Tensor` representing `response` dispersion, i.e., as in:
        `p(y|theta) := exp((y theta - A(theta)) / dispersion)`. Must broadcast
        with rows of `model_matrix`.
        Default value: `None` (i.e., "no dispersion").

    Returns:
      is_converged: `bool` `Tensor`.
    """
    arg_11 = (
        tf.norm(
            tensor=arg_4 - arg_6,
            ord=arg_1,
            axis=-1) /
        (1. +
         tf.norm(tensor=arg_4, ord=arg_1, axis=-1)))
    return (arg_3 > 0) & tf.reduce_all(
        input_tensor=arg_11 < arg_0)

  return convergence_criteria_fn


def Func(arg_0,
                 arg_1,
                 arg_2,
                 arg_3,
                 arg_4,
                 arg_5=None):
  """Helper to `fit` which sanitizes input args.

  Args:
    model_matrix: (Batch of) `float`-like, matrix-shaped `Tensor` where each row
      represents a sample's features.
    response: (Batch of) vector-shaped `Tensor` where each element represents a
      sample's observed response (to the corresponding row of features). Must
      have same `dtype` as `model_matrix`.
    model_coefficients: Optional (batch of) vector-shaped `Tensor` representing
      the model coefficients, one for each column in `model_matrix`. Must have
      same `dtype` as `model_matrix`.
      Default value: `tf.zeros(tf.shape(model_matrix)[-1], model_matrix.dtype)`.
    predicted_linear_response: Optional `Tensor` with `shape`, `dtype` matching
      `response`; represents `offset` shifted initial linear predictions based
      on current `model_coefficients`.
      Default value: `offset` if `model_coefficients is None`, and
      `tf.linalg.matvec(model_matrix, model_coefficients_start) + offset`
      otherwise.
    offset: Optional `Tensor` with `shape`, `dtype` matching `response`;
      represents constant shift applied to `predicted_linear_response`.
      Default value: `None` (i.e., `tf.zeros_like(response)`).
    name: Python `str` used as name prefix to ops created by this function.
      Default value: `"Func"`.

  Returns:
    model_matrix: A `Tensor` with `shape`, `dtype` and values of the
      `model_matrix` argument.
    response: A `Tensor` with `shape`, `dtype` and values of the
      `response` argument.
    model_coefficients_start: A `Tensor` with `shape`, `dtype` and
      values of the `model_coefficients_start` argument if specified.
      A (batch of) vector-shaped `Tensors` with `dtype` matching `model_matrix`
      containing the default starting point otherwise.
    predicted_linear_response:  A `Tensor` with `shape`, `dtype` and
      values of the `predicted_linear_response` argument if specified.
      A `Tensor` with `shape`, `dtype` matching `response` containing the
      default value otherwise.
    offset: A `Tensor` with `shape`, `dtype` and values of the `offset` argument
      if specified or `None` otherwise.
  """
  arg_6 = [arg_0, arg_1, arg_2,
                arg_3, arg_4]
  with tf.compat.v1.name_scope(arg_5, 'Func', arg_6):
    arg_7 = dtype_util.common_dtype(arg_6, np.float32)

    arg_0 = tf.convert_to_tensor(
        value=arg_0, arg_7=arg_7, arg_5='model_matrix')

    if arg_4 is not None:
      arg_4 = tf.convert_to_tensor(value=arg_4, arg_7=arg_7, arg_5='offset')

    arg_1 = tf.convert_to_tensor(
        value=arg_1, arg_7=arg_7, arg_5='response')

    arg_8 = arg_2 is None
    if arg_8:
      # User did not supply model coefficients; assume they're all zero.
      arg_9 = tf.shape(input=arg_0)[:-2]
      arg_10 = tf.shape(input=arg_0)[-1]
      arg_2 = tf.zeros(
          shape=tf.concat([arg_9, [arg_10]], axis=0),
          arg_7=arg_7, arg_5='model_coefficients')
    else:
      # User did supply model coefficients; convert to Tensor in case it's
      # numpy or literal.
      arg_2 = tf.convert_to_tensor(
          value=arg_2, arg_7=arg_7, arg_5='model_coefficients')

    if arg_3 is None:
      if arg_8:
        # Since we're using zeros for model_coefficients, we know the predicted
        # linear response will also be all zeros.
        if arg_4 is None:
          arg_3 = tf.zeros_like(
              arg_1, arg_7, arg_5='predicted_linear_response')
        else:
          arg_3 = tf.broadcast_to(
              arg_4,
              tf.shape(input=arg_1),
              arg_5='predicted_linear_response')
      else:
        # We were given model_coefficients but not the predicted linear
        # response.
        arg_3 = calculate_linear_predictor(
            arg_0, arg_2, arg_4)
    else:
      arg_3 = tf.convert_to_tensor(
          value=arg_3,
          arg_7=arg_7,
          arg_5='predicted_linear_response')

  return [
      arg_0,
      arg_1,
      arg_2,
      arg_3,
      arg_4,
  ]


def Func(arg_0):
  """Helper function for statically evaluating predicates in `cond`."""
  if arg_0 in {0, 1}:  # Accept 1/0 as valid boolean values
    arg_1 = bool(arg_0)
  elif isinstance(arg_0, bool):
    arg_1 = arg_0
  elif isinstance(arg_0, tf.Tensor):
    arg_1 = tf.get_static_value(arg_0)

    # TODO(jamieas): remove the dependency on `pywrap_tensorflow`.
    # pylint: disable=protected-access
    if arg_1 is None:
      arg_1 = c_api.TF_TryEvaluateConstant_wrapper(arg_0.graph._c_graph,
                                                        arg_0._as_tf_output())
    # pylint: enable=protected-access

  else:
    raise TypeError('`pred` must be a Tensor, or a Python bool, or 1 or 0. '
                    'Found instead: {}'.format(arg_0))
  return arg_1


def Func(arg_0, arg_1=None):
  """Computes `rank` given a `Tensor`'s `shape`."""

  if arg_1 is None:
    arg_2 = (arg_0() if callable(arg_0)
                    else arg_0)
    if (hasattr(arg_2, 'shape') and
        hasattr(arg_2.shape, 'num_elements')):
      arg_3 = tensorshape_util.num_elements(arg_2.shape)
    else:
      arg_3 = len(arg_2)
    arg_4 = lambda: tf.size(input=arg_2)
  else:
    arg_3 = tensorshape_util.rank(arg_1)
    arg_4 = lambda: tf.size(input=arg_0()  # pylint: disable=g-long-lambda
                               if callable(arg_0)
                               else arg_0)
  return arg_4() if arg_3 is None else arg_3


def Func(arg_0, arg_1=None, arg_2=False, arg_3='smart_Func'):
  """Like tf.Func, except attempts to statically evaluate predicates.

  If any predicate in `pred_fn_pairs` is a bool or has a constant value, the
  associated callable will be called or omitted depending on its value.
  Otherwise this functions like tf.Func.

  Args:
    pred_fn_pairs: Dict or list of pairs of a boolean scalar tensor and a
                   callable which returns a list of tensors.
    default: Optional callable that returns a list of tensors.
    exclusive: True iff at most one predicate is allowed to evaluate to `True`.
    name: A name for this operation (optional).

  Returns:
    The tensors returned by the first pair whose predicate evaluated to True, or
    those returned by `default` if none does.

  Raises:
    TypeError: If `pred_fn_pairs` is not a list/dictionary.
    TypeError: If `pred_fn_pairs` is a list but does not contain 2-tuples.
    TypeError: If `fns[i]` is not callable for any i, or `default` is not
               callable.
  """
  return control_flow_ops._Func_helper(  # pylint: disable=protected-access
      cond, arg_0, arg_1, arg_2, arg_3, allow_python_preds=True)


def Func(arg_0, arg_1=None, arg_2=None, arg_3=None):
    """Helper function to standardize op scope."""
    with tf.compat.v1.name_scope(arg_0.name):
      with tf.compat.v1.name_scope(
          arg_1, arg_2, arg_3=arg_3 or []) as scope:
        yield scope