class_docstr: A stateless base class for Gaussian process models, that is, those of the
  form
  
  .. math::
     :nowrap:
  
     \begin{align}
         \theta        & \sim p(\theta) \\
         f             & \sim \mathcal{GP}(m(x), k(x, x'; \theta)) \\
         f_i           & = f(x_i) \\
         y_i \,|\, f_i & \sim p(y_i|f_i)
     \end{align}
  
  This class mostly adds functionality for predictions. To use it, inheriting
  classes must define a predict_f function, which computes the means and
  variances of the latent function.
  
  These predictions are then pushed through the likelihood to obtain means
  and variances of held out data, self.predict_y.
  
  The predictions can also be used to compute the (log) density of held-out
  data via self.predict_log_density.
  
  It is also possible to draw samples from the latent GPs using
  self.predict_f_samples.
  
  If you are new to GPflow, see our :doc:`../../../../getting_started` for examples on how to use
  a model.
  
  :param kernel: Covariance function. $k$ above.
  :param likelihood: The likelihood of $y_i$, given $f_i$.
  :param mean_function: Mean of $f$.
  :param num_latent_gps: The number of latent GPs - the output dimension of $f$.
docstr: Calculates the number of latent GPs required given the number of
  outputs `output_dim` and the type of likelihood and kernel.
  
  Note: It's not nice for `GPModel` to need to be aware of specific
  likelihoods as here. However, `num_latent_gps` is a bit more broken in
  general, we should fix this in the future. There are also some slightly
  problematic assumptions re the output dimensions of mean_function.
  See https://github.com/GPflow/GPflow/issues/1343
docstr_tok: ["Calculates","the","number","of","latent","GPs","required","given","the","number","of","outputs","`","output_dim","`","and","the","type","of","likelihood","and","kernel",".","Note",":","It","'s","not","nice","for","`","GPModel","`","to","need","to","be","aware","of","specific","likelihoods","as","here",".","However",",","`","num_latent_gps","`","is","a","bit","more","broken","in","general",",","we","should","fix","this","in","the","future",".","There","are","also","some","slightly","problematic","assumptions","re","the","output","dimensions","of","mean_function",".","See","https",":","\/\/github.com\/GPflow\/GPflow\/issues\/1343"]
code: def calc_num_latent_gps(
      kernel: Kernel, likelihood: Likelihood, output_dim: int
  ) -> int:
      """
      Calculates the number of latent GPs required given the number of
      outputs `output_dim` and the type of likelihood and kernel.
  
      Note: It's not nice for `GPModel` to need to be aware of specific
      likelihoods as here. However, `num_latent_gps` is a bit more broken in
      general, we should fix this in the future. There are also some slightly
      problematic assumptions re the output dimensions of mean_function.
      See https://github.com/GPflow/GPflow/issues/1343
      """
      if isinstance(kernel, MultioutputKernel):
          # MultioutputKernels already have num_latent_gps attributes
          num_latent_gps: int = kernel.num_latent_gps
      elif isinstance(likelihood, SwitchedLikelihood):
          # the SwitchedLikelihood partitions/stitches based on the last
          # column in Y, but we should not add a separate latent GP for this!
          # hence decrement by 1
          num_latent_gps = output_dim - 1
          assert num_latent_gps > 0
      else:
          num_latent_gps = output_dim
  
      return num_latent_gps
  
imports: import abc
  from typing import Any, Optional
  import tensorflow
  from check_shapes import check_shapes
  from ..base import InputData, MeanAndVariance, Module, RegressionData
  from ..conditionals.util import sample_mvn
  from ..kernels import Kernel, MultioutputKernel
  from ..likelihoods import Likelihood, SwitchedLikelihood
  from ..mean_functions import MeanFunction, Zero
  from ..utilities import assert_params_false, to_default_float
label_desc: Use image node_id 3 for calling the GPModel obj's underlying member method code with example usage: obj.calc_num_latent_gps(kernel, likelihood, output_dim) and returns: num_latent_gps