class_docstr: Hidden Markov model distribution.
  
  The `HiddenMarkovModel` distribution implements a (batch of) discrete hidden
  Markov models where the initial states, transition probabilities
  and observed states are all given by user-provided distributions.
  
  In this model, there is a sequence of integer-valued hidden states:
  `z[0], z[1], ..., z[num_steps - 1]` and a sequence of observed states:
  `x[0], ..., x[num_steps - 1]`.
  The distribution of `z[0]` is given by `initial_distribution`.
  The conditional probability of `z[i  +  1]` given `z[i]` is described by
  the batch of distributions in `transition_distribution`.
  For a batch of hidden Markov models, the coordinates before the rightmost one
  of the `transition_distribution` batch correspond to indices into the hidden
  Markov model batch. The rightmost coordinate of the batch is used to select
  which distribution `z[i + 1]` is drawn from.  The distributions corresponding
  to the probability of `z[i + 1]` conditional on `z[i] == k` is given by the
  elements of the batch whose rightmost coordinate is `k`.
  Similarly, the conditional distribution of `x[i]` given `z[i]` is given by
  the batch of `observation_distribution`.
  When the rightmost coordinate of `observation_distribution` is `k` it
  gives the conditional probabilities of `x[i]` given `z[i] == k`.
  The probability distribution associated with the `HiddenMarkovModel`
  distribution is the marginal distribution of `x[0],...,x[num_steps - 1]`.
  
  #### Examples
  
  ```python
  tfd = tfp.distributions
  
  # A simple weather model.
  
  # Represent a cold day with 0 and a hot day with 1.
  # Suppose the first day of a sequence has a 0.8 chance of being cold.
  # We can model this using the categorical distribution:
  
  initial_distribution = tfd.Categorical(probs=[0.8, 0.2])
  
  # Suppose a cold day has a 30% chance of being followed by a hot day
  # and a hot day has a 20% chance of being followed by a cold day.
  # We can model this as:
  
  transition_distribution = tfd.Categorical(probs=[[0.7, 0.3],
                                                   [0.2, 0.8]])
  
  # Suppose additionally that on each day the temperature is
  # normally distributed with mean and standard deviation 0 and 5 on
  # a cold day and mean and standard deviation 15 and 10 on a hot day.
  # We can model this with:
  
  observation_distribution = tfd.Normal(loc=[0., 15.], scale=[5., 10.])
  
  # We can combine these distributions into a single week long
  # hidden Markov model with:
  
  model = tfd.HiddenMarkovModel(
      initial_distribution=initial_distribution,
      transition_distribution=transition_distribution,
      observation_distribution=observation_distribution,
      num_steps=7)
  
  # The expected temperatures for each day are given by:
  
  model.mean()  # shape [7], elements approach 9.0
  
  # The log pdf of a week of temperature 0 is:
  
  model.log_prob(tf.zeros(shape=[7]))
  ```
  
  #### References
  [1] https://en.wikipedia.org/wiki/Hidden_Markov_model
class_docstr_tok: ["Hidden","Markov","model","distribution",".","The","`","HiddenMarkovModel","`","distribution","implements","a","(","batch","of",")","discrete","hidden","Markov","models","where","the","initial","states",",","transition","probabilities","and","observed","states","are","all","given","by","user-provided","distributions",".","In","this","model",",","there","is","a","sequence","of","integer-valued","hidden","states",":","`","z","[","0","]",",","z","[","1","]",",","...",",","z","[","num_steps","-","1","]","`","and","a","sequence","of","observed","states",":","`","x","[","0","]",",","...",",","x","[","num_steps","-","1","]","`",".","The","distribution","of","`","z","[","0","]","`","is","given","by","`","initial_distribution","`",".","The","conditional","probability","of","`","z","[","i","+","1","]","`","given","`","z","[","i","]","`","is","described","by","the","batch","of","distributions","in","`","transition_distribution","`",".","For","a","batch","of","hidden","Markov","models",",","the","coordinates","before","the","rightmost","one","of","the","`","transition_distribution","`","batch","correspond","to","indices","into","the","hidden","Markov","model","batch",".","The","rightmost","coordinate","of","the","batch","is","used","to","select","which","distribution","`","z","[","i","+","1","]","`","is","drawn","from",".","The","distributions","corresponding","to","the","probability","of","`","z","[","i","+","1","]","`","conditional","on","`","z","[","i","]","==","k","`","is","given","by","the","elements","of","the","batch","whose","rightmost","coordinate","is","`","k","`",".","Similarly",",","the","conditional","distribution","of","`","x","[","i","]","`","given","`","z","[","i","]","`","is","given","by","the","batch","of","`","observation_distribution","`",".","When","the","rightmost","coordinate","of","`","observation_distribution","`","is","`","k","`","it","gives","the","conditional","probabilities","of","`","x","[","i","]","`","given","`","z","[","i","]","==","k","`",".","The","probability","distribution","associated","with","the","`","HiddenMarkovModel","`","distribution","is","the","marginal","distribution","of","`","x","[","0","]",",","...",",","x","[","num_steps","-","1","]","`",".","#","#","#","#","Examples","``","`","python","tfd","=","tfp.distributions","#","A","simple","weather","model",".","#","Represent","a","cold","day","with","0","and","a","hot","day","with","1",".","#","Suppose","the","first","day","of","a","sequence","has","a","0.8","chance","of","being","cold",".","#","We","can","model","this","using","the","categorical","distribution",":","initial_distribution","=","tfd.Categorical","(","probs=","[","0.8",",","0.2","]",")","#","Suppose","a","cold","day","has","a","30","%","chance","of","being","followed","by","a","hot","day","#","and","a","hot","day","has","a","20","%","chance","of","being","followed","by","a","cold","day",".","#","We","can","model","this","as",":","transition_distribution","=","tfd.Categorical","(","probs=","[","[","0.7",",","0.3","]",",","[","0.2",",","0.8","]","]",")","#","Suppose","additionally","that","on","each","day","the","temperature","is","#","normally","distributed","with","mean","and","standard","deviation","0","and","5","on","#","a","cold","day","and","mean","and","standard","deviation","15","and","10","on","a","hot","day",".","#","We","can","model","this","with",":","observation_distribution","=","tfd.Normal","(","loc=","[","0.",",","15",".","]",",","scale=","[","5.",",","10",".","]",")","#","We","can","combine","these","distributions","into","a","single","week","long","#","hidden","Markov","model","with",":","model","=","tfd.HiddenMarkovModel","(","initial_distribution=initial_distribution",",","transition_distribution=transition_distribution",",","observation_distribution=observation_distribution",",","num_steps=7",")","#","The","expected","temperatures","for","each","day","are","given","by",":","model.mean","(",")","#","shape","[","7","]",",","elements","approach","9.0","#","The","log","pdf","of","a","week","of","temperature","0","is",":","model.log_prob","(","tf.zeros","(","shape=","[","7","]",")",")","``","`","#","#","#","#","References","[","1","]","https",":","\/\/en.wikipedia.org\/wiki\/Hidden_Markov_model"]
code: def _parameter_control_dependencies(self, is_init):
      assertions = []
  
      # Check num_steps is a scalar that's at least 1.
      if is_init != tensor_util.is_ref(self.num_steps):
          num_steps = tf.convert_to_tensor(self.num_steps)
          num_steps_ = tf.get_static_value(num_steps)
          if num_steps_ is not None:
              if np.ndim(num_steps_) != 0:
                  raise ValueError(
                      "`num_steps` must be a scalar but it has rank {}".format(
                          np.ndim(num_steps_)
                      )
                  )
              if num_steps_ < 1:
                  raise ValueError("`num_steps` must be at least 1.")
          elif self.validate_args:
              message = "`num_steps` must be a scalar"
              assertions.append(
                  assert_util.assert_rank_at_most(
                      self.num_steps, 0, message=message
                  )
              )
              assertions.append(
                  assert_util.assert_greater_equal(
                      num_steps,
                      1,
                      message="`num_steps` must be at least 1.",
                  )
              )
  
      # Check that the initial distribution has scalar events over the
      # integers.
      if is_init and not dtype_util.is_integer(
          self.initial_distribution.dtype
      ):
          raise ValueError(
              "`initial_distribution.dtype` ({}) is not over integers".format(
                  dtype_util.name(self.initial_distribution.dtype)
              )
          )
  
      if (
          tensorshape_util.rank(self.initial_distribution.event_shape)
          is not None
      ):
          if (
              tensorshape_util.rank(
                  self.initial_distribution.event_shape
              )
              != 0
          ):
              raise ValueError(
                  "`initial_distribution` must have scalar `event_dim`s"
              )
      elif self.validate_args:
          assertions += [
              assert_util.assert_equal(
                  ps.size(
                      self.initial_distribution.event_shape_tensor()
                  ),
                  0,
                  message="`initial_distribution` must have scalar `event_dim`s",
              ),
          ]
  
      # Check that the transition distribution is over the integers.
      if is_init and not dtype_util.is_integer(
          self.transition_distribution.dtype
      ):
          raise ValueError(
              "`transition_distribution.dtype` ({}) is not over integers".format(
                  dtype_util.name(self.transition_distribution.dtype)
              )
          )
  
      # Check observations have non-scalar batches.
      # The graph version of this assertion is incorporated as
      # a control dependency of the transition/observation
      # compatibility test.
      if (
          tensorshape_util.rank(
              self.observation_distribution.batch_shape
          )
          == 0
      ):
          raise ValueError(
              "`observation_distribution` can't have scalar batches"
          )
  
      # Check transitions have non-scalar batches.
      # The graph version of this assertion is incorporated as
      # a control dependency of the transition/observation
      # compatibility test.
      if (
          tensorshape_util.rank(
              self.transition_distribution.batch_shape
          )
          == 0
      ):
          raise ValueError(
              "`transition_distribution` can't have scalar batches"
          )
  
      # Check compatibility of transition distribution and observation
      # distribution.
      tdbs = self.transition_distribution.batch_shape
      odbs = self.observation_distribution.batch_shape
      if (
          tensorshape_util.dims(tdbs) is not None
          and tf.compat.dimension_value(odbs[-1]) is not None
      ):
          if tf.compat.dimension_value(
              tdbs[-1]
          ) != tf.compat.dimension_value(odbs[-1]):
              raise ValueError(
                  "`transition_distribution` and `observation_distribution` "
                  "must agree on last dimension of batch size"
              )
          static_num_steps = tf.compat.dimension_value(
              self._static_event_shape[0]
          )
          if (
              self._time_varying_observation_distribution
              and static_num_steps is not None
              and tf.compat.dimension_value(odbs[-2]) is not None
              and tf.compat.dimension_value(odbs[-2])
              != static_num_steps
          ):
              raise ValueError(
                  "A time-varying `observation_distribution` must have a first "
                  "batch dimension that matches num_steps."
              )
          if (
              self._time_varying_transition_distribution
              and static_num_steps is not None
              and tf.compat.dimension_value(tdbs[-2]) is not None
              and tf.compat.dimension_value(tdbs[-2])
              != (static_num_steps - 1)
          ):
              raise ValueError(
                  "A time-varying `transition_distribution` must have a first "
                  "batch dimension that matches num_steps - 1."
              )
      elif self.validate_args:
          tdbs = self.transition_distribution.batch_shape_tensor()
          odbs = self.observation_distribution.batch_shape_tensor()
          preconditions = []
          preconditions.append(
              assert_util.assert_greater(
                  ps.size(tdbs),
                  0,
                  message=(
                      "`transition_distribution` can't have scalar "
                      "batches"
                  ),
              )
          )
          preconditions.append(
              assert_util.assert_greater(
                  ps.size(odbs),
                  0,
                  message=(
                      "`observation_distribution` can't have scalar "
                      "batches"
                  ),
              )
          )
          if self._time_varying_transition_distribution:
              preconditions.append(
                  assert_util.assert_equal(
                      tdbs[-2],
                      tf.convert_to_tensor(self.num_steps - 1),
                      message=(
                          "A time-varying `transition_distribution` must have a "
                          "first batch dimension that matches num_steps - 1."
                      ),
                  )
              )
          if self._time_varying_observation_distribution:
              preconditions.append(
                  assert_util.assert_equal(
                      odbs[-2],
                      tf.convert_to_tensor(self.num_steps),
                      message=(
                          "A time-varying `observation_distribution` must have a "
                          "first batch dimension that matches num_steps."
                      ),
                  )
              )
          with tf.control_dependencies(preconditions):
              assertions += [
                  assert_util.assert_equal(
                      tdbs[-1],
                      odbs[-1],
                      message=(
                          "`transition_distribution` and "
                          "`observation_distribution` "
                          "must agree on last dimension of batch size"
                      ),
                  )
              ]
  
      return assertions
  
imports: import numpy
  import tensorflow.compat.v2
  from tensorflow_probability.python.distributions import categorical
  from tensorflow_probability.python.distributions import distribution
  from tensorflow_probability.python.internal import assert_util
  from tensorflow_probability.python.internal import distribution_util
  from tensorflow_probability.python.internal import dtype_util
  from tensorflow_probability.python.internal import parameter_properties
  from tensorflow_probability.python.internal import prefer_static
  from tensorflow_probability.python.internal import reparameterization
  from tensorflow_probability.python.internal import samplers
  from tensorflow_probability.python.internal import tensor_util
  from tensorflow_probability.python.internal import tensorshape_util
label_desc: Use image node_id 26 for calling the HiddenMarkovModel obj's underlying member method code with example usage: obj._parameter_control_dependencies(is_init) and returns: assertions