class_docstr: A non-identifiable model with a quartic measurement model.
  
  This distribution is defined in [1] as the posterior induced by the following
  model:
  
  ```none
  for i in range(ndims):
    theta[i] ~ Normal(loc=0, scale=1)
  F(theta) = theta[1]**2 + 3 * theta[0]**2 * (theta[0]**2 - 1)
  y ~ Normal(loc=F(theta), scale=noise_scale)
  ```
  
  with an observed `y = 1`. Note that if `ndims` is > 2, the additional
  dimensions are distributed as a standard normal.
  
  This distribution is notable for having density on a narrow manifold which
  requires small step sizes when using HMC. It also happens to be multi-modal (4
  modes), but the modes are not well separated and should not pose challenge to
  most inference methods.
  
  #### References
  
  1. Au, K. X., Graham, M. M., & Thiery, A. H. (2020). Manifold lifting: scaling
     MCMC to the vanishing noise regime. (2), 1-18. Retrieved from
     http://arxiv.org/abs/2003.03950
docstr: Construct the NonIdentifiableQuarticMeasurementModel model.
  
  Args:
    ndims: Python integer. Dimensionality of the distribution. Must be at
      least 2.
    noise_scale: Floating point Tensor. Scale of the observation noise.
    name: Python `str` name prefixed to Ops created by this class.
    pretty_name: A Python `str`. The pretty name of this model.
  
  Raises:
    ValueError: If ndims < 2.
docstr_tok: ["Construct","the","NonIdentifiableQuarticMeasurementModel","model",".","Args",":","ndims",":","Python","integer",".","Dimensionality","of","the","distribution",".","Must","be","at","least","2.","noise_scale",":","Floating","point","Tensor",".","Scale","of","the","observation","noise",".","name",":","Python","`","str","`","name","prefixed","to","Ops","created","by","this","class",".","pretty_name",":","A","Python","`","str","`",".","The","pretty","name","of","this","model",".","Raises",":","ValueError",":","If","ndims","<","2","."]
code: def __init__(
      self,
      ndims=2,
      noise_scale=0.1,
      name="non_identifiable_quartic_measurement_model",
      pretty_name="Non-Identifiable Quartic Measurement Model",
  ):
      """Construct the NonIdentifiableQuarticMeasurementModel model.
  
      Args:
        ndims: Python integer. Dimensionality of the distribution. Must be at
          least 2.
        noise_scale: Floating point Tensor. Scale of the observation noise.
        name: Python `str` name prefixed to Ops created by this class.
        pretty_name: A Python `str`. The pretty name of this model.
  
      Raises:
        ValueError: If ndims < 2.
      """
      if ndims < 2:
          raise ValueError(
              "ndims must be at least 2, saw: {}".format(ndims)
          )
  
      with tf.name_scope(name):
          sample_transformations = {
              "identity": model.Model.SampleTransformation(
                  fn=lambda params: params,
                  pretty_name="Identity",
                  ground_truth_mean=np.zeros(ndims),  # By symmetry.
              )
          }
  
          self._prior_dist = tfd.Sample(tfd.Normal(0.0, 1.0), ndims)
          self._noise_scale = tf.convert_to_tensor(
              noise_scale, dtype_hint=tf.float32
          )
  
      super(NonIdentifiableQuarticMeasurementModel, self).__init__(
          default_event_space_bijector=tfb.Identity(),
          event_shape=self._prior_dist.event_shape,
          dtype=self._prior_dist.dtype,
          name=name,
          pretty_name=pretty_name,
          sample_transformations=sample_transformations,
      )
  
file_path: probability/spinoffs/inference_gym/inference_gym/targets/non_identifiable_quartic.py
imports: import numpy
  import tensorflow.compat.v2
  import tensorflow_probability
  from inference_gym.targets import bayesian_model
  from inference_gym.targets import model
label_desc: Use image node_id 1 to create a new NonIdentifiableQuarticMeasurementModel object from inherited base classes: bayesian_model with example: obj = NonIdentifiableQuarticMeasurementModel(ndims, noise_scale, name, pretty_name)