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: Produce samples from the posterior latent function(s) at the input points.
  
  Currently, the method does not support `full_output_cov=True` and `full_cov=True`.
  
  :param Xnew:
      Input locations at which to draw samples.
  :param num_samples:
      Number of samples to draw.
      If `None`, a single sample is drawn and the return shape is [..., N, P],
      for any positive integer the return shape contains an extra batch
      dimension, [..., S, N, P], with S = num_samples and P is the number of outputs.
  :param full_cov:
      If True, draw correlated samples over the inputs. Computes the Cholesky over the
      dense covariance matrix of size [num_data, num_data].
      If False, draw samples that are uncorrelated over the inputs.
  :param full_output_cov:
      If True, draw correlated samples over the outputs.
      If False, draw samples that are uncorrelated over the outputs.
docstr_tok: ["Produce","samples","from","the","posterior","latent","function","(","s",")","at","the","input","points",".","Currently",",","the","method","does","not","support","`","full_output_cov=True","`","and","`","full_cov=True","`",".",":","param","Xnew",":","Input","locations","at","which","to","draw","samples",".",":","param","num_samples",":","Number","of","samples","to","draw",".","If","`","None","`",",","a","single","sample","is","drawn","and","the","return","shape","is","[","...",",","N",",","P","]",",","for","any","positive","integer","the","return","shape","contains","an","extra","batch","dimension",",","[","...",",","S",",","N",",","P","]",",","with","S","=","num_samples","and","P","is","the","number","of","outputs",".",":","param","full_cov",":","If","True",",","draw","correlated","samples","over","the","inputs",".","Computes","the","Cholesky","over","the","dense","covariance","matrix","of","size","[","num_data",",","num_data","]",".","If","False",",","draw","samples","that","are","uncorrelated","over","the","inputs",".",":","param","full_output_cov",":","If","True",",","draw","correlated","samples","over","the","outputs",".","If","False",",","draw","samples","that","are","uncorrelated","over","the","outputs","."]
code: def predict_f_samples(
      self,
      Xnew: InputData,
      num_samples: Optional[int] = None,
      full_cov: bool = True,
      full_output_cov: bool = False,
  ) -> tf.Tensor:
      """
      Produce samples from the posterior latent function(s) at the input points.
  
      Currently, the method does not support `full_output_cov=True` and `full_cov=True`.
  
      :param Xnew:
          Input locations at which to draw samples.
      :param num_samples:
          Number of samples to draw.
          If `None`, a single sample is drawn and the return shape is [..., N, P],
          for any positive integer the return shape contains an extra batch
          dimension, [..., S, N, P], with S = num_samples and P is the number of outputs.
      :param full_cov:
          If True, draw correlated samples over the inputs. Computes the Cholesky over the
          dense covariance matrix of size [num_data, num_data].
          If False, draw samples that are uncorrelated over the inputs.
      :param full_output_cov:
          If True, draw correlated samples over the outputs.
          If False, draw samples that are uncorrelated over the outputs.
      """
      if full_cov and full_output_cov:
          raise NotImplementedError(
              "The combination of both `full_cov` and `full_output_cov` is not supported."
          )
  
      # check below for shape info
      mean, cov = self.predict_f(
          Xnew, full_cov=full_cov, full_output_cov=full_output_cov
      )
      if full_cov:
          # mean: [..., N, P]
          # cov: [..., P, N, N]
          mean_for_sample = tf.linalg.adjoint(mean)  # [..., P, N]
          samples = sample_mvn(
              mean_for_sample, cov, full_cov, num_samples=num_samples
          )  # [..., (S), P, N]
          samples = tf.linalg.adjoint(samples)  # [..., (S), N, P]
      else:
          # mean: [..., N, P]
          # cov: [..., N, P] or [..., N, P, P]
          samples = sample_mvn(
              mean, cov, full_output_cov, num_samples=num_samples
          )  # [..., (S), N, P]
      return samples
  
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 5 for calling the GPModel obj's underlying member method code with example usage: obj.predict_f_samples(Xnew, num_samples, full_cov, full_output_cov) and returns: samples