We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
SwitchedLikelihood fails in conjunction with likelihoods relying on the quadrature fallback
Are there any tips and trick to using the Student T likelihood? Below is an example of some data that I have... similar to the gpflow example of a coregionalized model with a student T.  When I run the code below, I get this error.

```   File "/opt/conda/lib/python3.6/site-packages/gpflow-1.3.0-py3.6.egg/gpflow/quadrature.py", line 187, in eval_func
    feval = f(*Xs, **Ys)  # f should be elementwise: return shape N x H**Din
  File "/opt/conda/lib/python3.6/site-packages/gpflow-1.3.0-py3.6.egg/gpflow/decors.py", line 67, in tensor_mode_wrapper
    result = method(obj, *args, **kwargs)
  File "/opt/conda/lib/python3.6/site-packages/gpflow-1.3.0-py3.6.egg/gpflow/likelihoods.py", line 217, in logp
    return logdensities.student_t(Y, F, self.scale, self.df)
  File "/opt/conda/lib/python3.6/site-packages/gpflow-1.3.0-py3.6.egg/gpflow/logdensities.py", line 59, in student_t
    tf.log(1. + (1. / df) * (tf.square((x - mean) / scale)))
```

maybe a convergence error...? I have tried playing around with the jitter parameter and the degrees of freedom, but to no avail. Any ideas?

Thanks!

 Below is a minimal bug-reproducing example
```
import gpflow as gpflow
import numpy as np

idx = np.array([0]*12 + [1]*15 + [2]*36)
X_aug = np.c_[np.random.randn(12+15+36, 1), idx]
Y_aug = np.c_[np.random.randn(12+15+36, 1), idx]

k1 = gpflow.kernels.Matern32(1, variance=.1, active_dims=[0]) +gpflow.kernels.White(1)
coreg = gpflow.kernels.Coregion(1, output_dim=3, rank=3, active_dims=[1])
kern = k1 * coreg

# build a variational model. This likelihood switches between Student-T noise with different variances:
lik = gpflow.likelihoods.SwitchedLikelihood([gpflow.likelihoods.StudentT(), gpflow.likelihoods.StudentT(), gpflow.likelihoods.StudentT()])
m = gpflow.models.VGP(X_aug, Y_aug, kern=kern, likelihood=lik)
## optimization errors out
gpflow.train.ScipyOptimizer().minimize(m)
 

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `gpflow/models/model.py`
Content:
```
1 # Copyright 2016 James Hensman, Mark van der Wilk, Valentine Svensson, alexggmatthews, fujiisoup
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14 
15 import abc
16 
17 import numpy as np
18 import tensorflow as tf
19 
20 from .. import settings
21 from ..core.compilable import Build
22 from ..params import Parameterized, DataHolder
23 from ..decors import autoflow
24 from ..mean_functions import Zero
25 
26 
27 class Model(Parameterized):
28     def __init__(self, name=None):
29         """
30         Name is a string describing this model.
31         """
32         super(Model, self).__init__(name=name)
33         self._objective = None
34         self._likelihood_tensor = None
35 
36     @property
37     def objective(self):
38         return self._objective
39 
40     @property
41     def likelihood_tensor(self):
42         return self._likelihood_tensor
43 
44     @autoflow()
45     def compute_log_prior(self):
46         """Compute the log prior of the model."""
47         return self.prior_tensor
48 
49     @autoflow()
50     def compute_log_likelihood(self):
51         """Compute the log likelihood of the model."""
52         return self.likelihood_tensor
53 
54     def is_built(self, graph):
55         is_built = super().is_built(graph)
56         if is_built is not Build.YES:
57             return is_built
58         if self._likelihood_tensor is None:
59             return Build.NO
60         return Build.YES
61 
62     def build_objective(self):
63         likelihood = self._build_likelihood()
64         priors = []
65         for param in self.parameters:
66             unconstrained = param.unconstrained_tensor
67             constrained = param._build_constrained(unconstrained)
68             priors.append(param._build_prior(unconstrained, constrained))
69         prior = self._build_prior(priors)
70         return self._build_objective(likelihood, prior)
71 
72     def _clear(self):
73         super(Model, self)._clear()
74         self._likelihood_tensor = None
75         self._objective = None
76 
77     def _build(self):
78         super(Model, self)._build()
79         likelihood = self._build_likelihood()
80         prior = self.prior_tensor
81         objective = self._build_objective(likelihood, prior)
82         self._likelihood_tensor = likelihood
83         self._objective = objective
84 
85     def sample_feed_dict(self, sample):
86         tensor_feed_dict = {}
87         for param in self.parameters:
88             if not param.trainable: continue
89             constrained_value = sample[param.pathname]
90             unconstrained_value = param.transform.backward(constrained_value)
91             tensor = param.unconstrained_tensor
92             tensor_feed_dict[tensor] = unconstrained_value
93         return tensor_feed_dict
94 
95     def _build_objective(self, likelihood_tensor, prior_tensor):
96         func = tf.add(likelihood_tensor, prior_tensor, name='nonneg_objective')
97         return tf.negative(func, name='objective')
98 
99     @abc.abstractmethod
100     def _build_likelihood(self):
101         pass
102 
103 
104 class GPModel(Model):
105     r"""
106     A base class for Gaussian process models, that is, those of the form
107 
108     .. math::
109        :nowrap:
110 
111        \begin{align}
112        \theta & \sim p(\theta) \\
113        f       & \sim \mathcal{GP}(m(x), k(x, x'; \theta)) \\
114        f_i       & = f(x_i) \\
115        y_i\,|\,f_i     & \sim p(y_i|f_i)
116        \end{align}
117 
118     This class mostly adds functionality to compile predictions. To use it,
119     inheriting classes must define a build_predict function, which computes
120     the means and variances of the latent function. This gets compiled
121     similarly to build_likelihood in the Model class.
122 
123     These predictions are then pushed through the likelihood to obtain means
124     and variances of held out data, self.predict_y.
125 
126     The predictions can also be used to compute the (log) density of held-out
127     data via self.predict_density.
128 
129     For handling another data (Xnew, Ynew), set the new value to self.X and self.Y
130 
131     >>> m.X = Xnew
132     >>> m.Y = Ynew
133     """
134 
135     def __init__(self, X, Y, kern, likelihood, mean_function,
136                  num_latent=None, name=None):
137         super(GPModel, self).__init__(name=name)
138         self.num_latent = num_latent or Y.shape[1]
139         self.mean_function = mean_function or Zero(output_dim=self.num_latent)
140         self.kern = kern
141         self.likelihood = likelihood
142 
143         if isinstance(X, np.ndarray):
144             # X is a data matrix; each row represents one instance
145             X = DataHolder(X)
146         if isinstance(Y, np.ndarray):
147             # Y is a data matrix, rows correspond to the rows in X,
148             # columns are treated independently
149             Y = DataHolder(Y)
150         self.X, self.Y = X, Y
151 
152     @autoflow((settings.float_type, [None, None]))
153     def predict_f(self, Xnew):
154         """
155         Compute the mean and variance of the latent function(s) at the points
156         Xnew.
157         """
158         return self._build_predict(Xnew)
159 
160     @autoflow((settings.float_type, [None, None]))
161     def predict_f_full_cov(self, Xnew):
162         """
163         Compute the mean and covariance matrix of the latent function(s) at the
164         points Xnew.
165         """
166         return self._build_predict(Xnew, full_cov=True)
167 
168     @autoflow((settings.float_type, [None, None]), (tf.int32, []))
169     def predict_f_samples(self, Xnew, num_samples):
170         """
171         Produce samples from the posterior latent function(s) at the points
172         Xnew.
173         """
174         mu, var = self._build_predict(Xnew, full_cov=True)  # N x P, # P x N x N
175         jitter = tf.eye(tf.shape(mu)[0], dtype=settings.float_type) * settings.jitter
176         samples = []
177         for i in range(self.num_latent):
178             L = tf.cholesky(var[i, :, :] + jitter)
179             shape = tf.stack([tf.shape(L)[0], num_samples])
180             V = tf.random_normal(shape, dtype=settings.float_type)
181             samples.append(mu[:, i:i + 1] + tf.matmul(L, V))
182         return tf.transpose(tf.stack(samples))
183 
184     @autoflow((settings.float_type, [None, None]))
185     def predict_y(self, Xnew):
186         """
187         Compute the mean and variance of held-out data at the points Xnew
188         """
189         pred_f_mean, pred_f_var = self._build_predict(Xnew)
190         return self.likelihood.predict_mean_and_var(pred_f_mean, pred_f_var)
191 
192     @autoflow((settings.float_type, [None, None]), (settings.float_type, [None, None]))
193     def predict_density(self, Xnew, Ynew):
194         """
195         Compute the (log) density of the data Ynew at the points Xnew
196 
197         Note that this computes the log density of the data individually,
198         ignoring correlations between them. The result is a matrix the same
199         shape as Ynew containing the log densities.
200         """
201         pred_f_mean, pred_f_var = self._build_predict(Xnew)
202         return self.likelihood.predict_density(pred_f_mean, pred_f_var, Ynew)
203 
204     @abc.abstractmethod
205     def _build_predict(self, *args, **kwargs):
206         pass
207
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/gpflow/models/model.py b/gpflow/models/model.py
--- a/gpflow/models/model.py
+++ b/gpflow/models/model.py
@@ -22,6 +22,7 @@
 from ..params import Parameterized, DataHolder
 from ..decors import autoflow
 from ..mean_functions import Zero
+from ..likelihoods import SwitchedLikelihood
 
 
 class Model(Parameterized):
@@ -135,7 +136,22 @@
     def __init__(self, X, Y, kern, likelihood, mean_function,
                  num_latent=None, name=None):
         super(GPModel, self).__init__(name=name)
-        self.num_latent = num_latent or Y.shape[1]
+        if num_latent is None:
+            # Note: It's not nice for `Model` to need to be aware of specific
+            # likelihoods as here. However, `num_latent` is a bit more broken
+            # in general, specifically regarding multioutput kernels. We
+            # should fix this in the future.
+            # It also has slightly problematic assumptions re the output
+            # dimensions of mean_function.
+            num_latent = Y.shape[1]
+            if 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
+                assert num_latent >= 2
+                num_latent -= 1
+
+        self.num_latent = num_latent
         self.mean_function = mean_function or Zero(output_dim=self.num_latent)
         self.kern = kern
         self.likelihood = likelihood

{"golden_diff": "diff --git a/gpflow/models/model.py b/gpflow/models/model.py\n--- a/gpflow/models/model.py\n+++ b/gpflow/models/model.py\n@@ -22,6 +22,7 @@\n from ..params import Parameterized, DataHolder\n from ..decors import autoflow\n from ..mean_functions import Zero\n+from ..likelihoods import SwitchedLikelihood\n \n \n class Model(Parameterized):\n@@ -135,7 +136,22 @@\n     def __init__(self, X, Y, kern, likelihood, mean_function,\n                  num_latent=None, name=None):\n         super(GPModel, self).__init__(name=name)\n-        self.num_latent = num_latent or Y.shape[1]\n+        if num_latent is None:\n+            # Note: It's not nice for `Model` to need to be aware of specific\n+            # likelihoods as here. However, `num_latent` is a bit more broken\n+            # in general, specifically regarding multioutput kernels. We\n+            # should fix this in the future.\n+            # It also has slightly problematic assumptions re the output\n+            # dimensions of mean_function.\n+            num_latent = Y.shape[1]\n+            if isinstance(likelihood, SwitchedLikelihood):\n+                # the SwitchedLikelihood partitions/stitches based on the last\n+                # column in Y, but we should not add a separate latent GP for\n+                # this! hence decrement by 1\n+                assert num_latent >= 2\n+                num_latent -= 1\n+\n+        self.num_latent = num_latent\n         self.mean_function = mean_function or Zero(output_dim=self.num_latent)\n         self.kern = kern\n         self.likelihood = likelihood\n", "issue": "SwitchedLikelihood fails in conjunction with likelihoods relying on the quadrature fallback\nAre there any tips and trick to using the Student T likelihood? Below is an example of some data that I have... similar to the gpflow example of a coregionalized model with a student T.  When I run the code below, I get this error.\r\n\r\n```   File \"/opt/conda/lib/python3.6/site-packages/gpflow-1.3.0-py3.6.egg/gpflow/quadrature.py\", line 187, in eval_func\r\n    feval = f(*Xs, **Ys)  # f should be elementwise: return shape N x H**Din\r\n  File \"/opt/conda/lib/python3.6/site-packages/gpflow-1.3.0-py3.6.egg/gpflow/decors.py\", line 67, in tensor_mode_wrapper\r\n    result = method(obj, *args, **kwargs)\r\n  File \"/opt/conda/lib/python3.6/site-packages/gpflow-1.3.0-py3.6.egg/gpflow/likelihoods.py\", line 217, in logp\r\n    return logdensities.student_t(Y, F, self.scale, self.df)\r\n  File \"/opt/conda/lib/python3.6/site-packages/gpflow-1.3.0-py3.6.egg/gpflow/logdensities.py\", line 59, in student_t\r\n    tf.log(1. + (1. / df) * (tf.square((x - mean) / scale)))\r\n```\r\n\r\nmaybe a convergence error...? I have tried playing around with the jitter parameter and the degrees of freedom, but to no avail. Any ideas?\r\n\r\nThanks!\r\n\r\n Below is a minimal bug-reproducing example\r\n```\r\nimport gpflow as gpflow\r\nimport numpy as np\r\n\r\nidx = np.array([0]*12 + [1]*15 + [2]*36)\r\nX_aug = np.c_[np.random.randn(12+15+36, 1), idx]\r\nY_aug = np.c_[np.random.randn(12+15+36, 1), idx]\r\n\r\nk1 = gpflow.kernels.Matern32(1, variance=.1, active_dims=[0]) +gpflow.kernels.White(1)\r\ncoreg = gpflow.kernels.Coregion(1, output_dim=3, rank=3, active_dims=[1])\r\nkern = k1 * coreg\r\n\r\n# build a variational model. This likelihood switches between Student-T noise with different variances:\r\nlik = gpflow.likelihoods.SwitchedLikelihood([gpflow.likelihoods.StudentT(), gpflow.likelihoods.StudentT(), gpflow.likelihoods.StudentT()])\r\nm = gpflow.models.VGP(X_aug, Y_aug, kern=kern, likelihood=lik)\r\n## optimization errors out\r\ngpflow.train.ScipyOptimizer().minimize(m)\r\n \n", "before_files": [{"content": "# Copyright 2016 James Hensman, Mark van der Wilk, Valentine Svensson, alexggmatthews, fujiisoup\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nimport abc\n\nimport numpy as np\nimport tensorflow as tf\n\nfrom .. import settings\nfrom ..core.compilable import Build\nfrom ..params import Parameterized, DataHolder\nfrom ..decors import autoflow\nfrom ..mean_functions import Zero\n\n\nclass Model(Parameterized):\n    def __init__(self, name=None):\n        \"\"\"\n        Name is a string describing this model.\n        \"\"\"\n        super(Model, self).__init__(name=name)\n        self._objective = None\n        self._likelihood_tensor = None\n\n    @property\n    def objective(self):\n        return self._objective\n\n    @property\n    def likelihood_tensor(self):\n        return self._likelihood_tensor\n\n    @autoflow()\n    def compute_log_prior(self):\n        \"\"\"Compute the log prior of the model.\"\"\"\n        return self.prior_tensor\n\n    @autoflow()\n    def compute_log_likelihood(self):\n        \"\"\"Compute the log likelihood of the model.\"\"\"\n        return self.likelihood_tensor\n\n    def is_built(self, graph):\n        is_built = super().is_built(graph)\n        if is_built is not Build.YES:\n            return is_built\n        if self._likelihood_tensor is None:\n            return Build.NO\n        return Build.YES\n\n    def build_objective(self):\n        likelihood = self._build_likelihood()\n        priors = []\n        for param in self.parameters:\n            unconstrained = param.unconstrained_tensor\n            constrained = param._build_constrained(unconstrained)\n            priors.append(param._build_prior(unconstrained, constrained))\n        prior = self._build_prior(priors)\n        return self._build_objective(likelihood, prior)\n\n    def _clear(self):\n        super(Model, self)._clear()\n        self._likelihood_tensor = None\n        self._objective = None\n\n    def _build(self):\n        super(Model, self)._build()\n        likelihood = self._build_likelihood()\n        prior = self.prior_tensor\n        objective = self._build_objective(likelihood, prior)\n        self._likelihood_tensor = likelihood\n        self._objective = objective\n\n    def sample_feed_dict(self, sample):\n        tensor_feed_dict = {}\n        for param in self.parameters:\n            if not param.trainable: continue\n            constrained_value = sample[param.pathname]\n            unconstrained_value = param.transform.backward(constrained_value)\n            tensor = param.unconstrained_tensor\n            tensor_feed_dict[tensor] = unconstrained_value\n        return tensor_feed_dict\n\n    def _build_objective(self, likelihood_tensor, prior_tensor):\n        func = tf.add(likelihood_tensor, prior_tensor, name='nonneg_objective')\n        return tf.negative(func, name='objective')\n\n    @abc.abstractmethod\n    def _build_likelihood(self):\n        pass\n\n\nclass GPModel(Model):\n    r\"\"\"\n    A base class for Gaussian process models, that is, those of the form\n\n    .. math::\n       :nowrap:\n\n       \\begin{align}\n       \\theta & \\sim p(\\theta) \\\\\n       f       & \\sim \\mathcal{GP}(m(x), k(x, x'; \\theta)) \\\\\n       f_i       & = f(x_i) \\\\\n       y_i\\,|\\,f_i     & \\sim p(y_i|f_i)\n       \\end{align}\n\n    This class mostly adds functionality to compile predictions. To use it,\n    inheriting classes must define a build_predict function, which computes\n    the means and variances of the latent function. This gets compiled\n    similarly to build_likelihood in the Model class.\n\n    These predictions are then pushed through the likelihood to obtain means\n    and variances of held out data, self.predict_y.\n\n    The predictions can also be used to compute the (log) density of held-out\n    data via self.predict_density.\n\n    For handling another data (Xnew, Ynew), set the new value to self.X and self.Y\n\n    >>> m.X = Xnew\n    >>> m.Y = Ynew\n    \"\"\"\n\n    def __init__(self, X, Y, kern, likelihood, mean_function,\n                 num_latent=None, name=None):\n        super(GPModel, self).__init__(name=name)\n        self.num_latent = num_latent or Y.shape[1]\n        self.mean_function = mean_function or Zero(output_dim=self.num_latent)\n        self.kern = kern\n        self.likelihood = likelihood\n\n        if isinstance(X, np.ndarray):\n            # X is a data matrix; each row represents one instance\n            X = DataHolder(X)\n        if isinstance(Y, np.ndarray):\n            # Y is a data matrix, rows correspond to the rows in X,\n            # columns are treated independently\n            Y = DataHolder(Y)\n        self.X, self.Y = X, Y\n\n    @autoflow((settings.float_type, [None, None]))\n    def predict_f(self, Xnew):\n        \"\"\"\n        Compute the mean and variance of the latent function(s) at the points\n        Xnew.\n        \"\"\"\n        return self._build_predict(Xnew)\n\n    @autoflow((settings.float_type, [None, None]))\n    def predict_f_full_cov(self, Xnew):\n        \"\"\"\n        Compute the mean and covariance matrix of the latent function(s) at the\n        points Xnew.\n        \"\"\"\n        return self._build_predict(Xnew, full_cov=True)\n\n    @autoflow((settings.float_type, [None, None]), (tf.int32, []))\n    def predict_f_samples(self, Xnew, num_samples):\n        \"\"\"\n        Produce samples from the posterior latent function(s) at the points\n        Xnew.\n        \"\"\"\n        mu, var = self._build_predict(Xnew, full_cov=True)  # N x P, # P x N x N\n        jitter = tf.eye(tf.shape(mu)[0], dtype=settings.float_type) * settings.jitter\n        samples = []\n        for i in range(self.num_latent):\n            L = tf.cholesky(var[i, :, :] + jitter)\n            shape = tf.stack([tf.shape(L)[0], num_samples])\n            V = tf.random_normal(shape, dtype=settings.float_type)\n            samples.append(mu[:, i:i + 1] + tf.matmul(L, V))\n        return tf.transpose(tf.stack(samples))\n\n    @autoflow((settings.float_type, [None, None]))\n    def predict_y(self, Xnew):\n        \"\"\"\n        Compute the mean and variance of held-out data at the points Xnew\n        \"\"\"\n        pred_f_mean, pred_f_var = self._build_predict(Xnew)\n        return self.likelihood.predict_mean_and_var(pred_f_mean, pred_f_var)\n\n    @autoflow((settings.float_type, [None, None]), (settings.float_type, [None, None]))\n    def predict_density(self, Xnew, Ynew):\n        \"\"\"\n        Compute the (log) density of the data Ynew at the points Xnew\n\n        Note that this computes the log density of the data individually,\n        ignoring correlations between them. The result is a matrix the same\n        shape as Ynew containing the log densities.\n        \"\"\"\n        pred_f_mean, pred_f_var = self._build_predict(Xnew)\n        return self.likelihood.predict_density(pred_f_mean, pred_f_var, Ynew)\n\n    @abc.abstractmethod\n    def _build_predict(self, *args, **kwargs):\n        pass\n", "path": "gpflow/models/model.py"}], "after_files": [{"content": "# Copyright 2016 James Hensman, Mark van der Wilk, Valentine Svensson, alexggmatthews, fujiisoup\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nimport abc\n\nimport numpy as np\nimport tensorflow as tf\n\nfrom .. import settings\nfrom ..core.compilable import Build\nfrom ..params import Parameterized, DataHolder\nfrom ..decors import autoflow\nfrom ..mean_functions import Zero\nfrom ..likelihoods import SwitchedLikelihood\n\n\nclass Model(Parameterized):\n    def __init__(self, name=None):\n        \"\"\"\n        Name is a string describing this model.\n        \"\"\"\n        super(Model, self).__init__(name=name)\n        self._objective = None\n        self._likelihood_tensor = None\n\n    @property\n    def objective(self):\n        return self._objective\n\n    @property\n    def likelihood_tensor(self):\n        return self._likelihood_tensor\n\n    @autoflow()\n    def compute_log_prior(self):\n        \"\"\"Compute the log prior of the model.\"\"\"\n        return self.prior_tensor\n\n    @autoflow()\n    def compute_log_likelihood(self):\n        \"\"\"Compute the log likelihood of the model.\"\"\"\n        return self.likelihood_tensor\n\n    def is_built(self, graph):\n        is_built = super().is_built(graph)\n        if is_built is not Build.YES:\n            return is_built\n        if self._likelihood_tensor is None:\n            return Build.NO\n        return Build.YES\n\n    def build_objective(self):\n        likelihood = self._build_likelihood()\n        priors = []\n        for param in self.parameters:\n            unconstrained = param.unconstrained_tensor\n            constrained = param._build_constrained(unconstrained)\n            priors.append(param._build_prior(unconstrained, constrained))\n        prior = self._build_prior(priors)\n        return self._build_objective(likelihood, prior)\n\n    def _clear(self):\n        super(Model, self)._clear()\n        self._likelihood_tensor = None\n        self._objective = None\n\n    def _build(self):\n        super(Model, self)._build()\n        likelihood = self._build_likelihood()\n        prior = self.prior_tensor\n        objective = self._build_objective(likelihood, prior)\n        self._likelihood_tensor = likelihood\n        self._objective = objective\n\n    def sample_feed_dict(self, sample):\n        tensor_feed_dict = {}\n        for param in self.parameters:\n            if not param.trainable: continue\n            constrained_value = sample[param.pathname]\n            unconstrained_value = param.transform.backward(constrained_value)\n            tensor = param.unconstrained_tensor\n            tensor_feed_dict[tensor] = unconstrained_value\n        return tensor_feed_dict\n\n    def _build_objective(self, likelihood_tensor, prior_tensor):\n        func = tf.add(likelihood_tensor, prior_tensor, name='nonneg_objective')\n        return tf.negative(func, name='objective')\n\n    @abc.abstractmethod\n    def _build_likelihood(self):\n        pass\n\n\nclass GPModel(Model):\n    r\"\"\"\n    A base class for Gaussian process models, that is, those of the form\n\n    .. math::\n       :nowrap:\n\n       \\begin{align}\n       \\theta & \\sim p(\\theta) \\\\\n       f       & \\sim \\mathcal{GP}(m(x), k(x, x'; \\theta)) \\\\\n       f_i       & = f(x_i) \\\\\n       y_i\\,|\\,f_i     & \\sim p(y_i|f_i)\n       \\end{align}\n\n    This class mostly adds functionality to compile predictions. To use it,\n    inheriting classes must define a build_predict function, which computes\n    the means and variances of the latent function. This gets compiled\n    similarly to build_likelihood in the Model class.\n\n    These predictions are then pushed through the likelihood to obtain means\n    and variances of held out data, self.predict_y.\n\n    The predictions can also be used to compute the (log) density of held-out\n    data via self.predict_density.\n\n    For handling another data (Xnew, Ynew), set the new value to self.X and self.Y\n\n    >>> m.X = Xnew\n    >>> m.Y = Ynew\n    \"\"\"\n\n    def __init__(self, X, Y, kern, likelihood, mean_function,\n                 num_latent=None, name=None):\n        super(GPModel, self).__init__(name=name)\n        if num_latent is None:\n            # Note: It's not nice for `Model` to need to be aware of specific\n            # likelihoods as here. However, `num_latent` is a bit more broken\n            # in general, specifically regarding multioutput kernels. We\n            # should fix this in the future.\n            # It also has slightly problematic assumptions re the output\n            # dimensions of mean_function.\n            num_latent = Y.shape[1]\n            if isinstance(likelihood, SwitchedLikelihood):\n                # the SwitchedLikelihood partitions/stitches based on the last\n                # column in Y, but we should not add a separate latent GP for\n                # this! hence decrement by 1\n                assert num_latent >= 2\n                num_latent -= 1\n\n        self.num_latent = num_latent\n        self.mean_function = mean_function or Zero(output_dim=self.num_latent)\n        self.kern = kern\n        self.likelihood = likelihood\n\n        if isinstance(X, np.ndarray):\n            # X is a data matrix; each row represents one instance\n            X = DataHolder(X)\n        if isinstance(Y, np.ndarray):\n            # Y is a data matrix, rows correspond to the rows in X,\n            # columns are treated independently\n            Y = DataHolder(Y)\n        self.X, self.Y = X, Y\n\n    @autoflow((settings.float_type, [None, None]))\n    def predict_f(self, Xnew):\n        \"\"\"\n        Compute the mean and variance of the latent function(s) at the points\n        Xnew.\n        \"\"\"\n        return self._build_predict(Xnew)\n\n    @autoflow((settings.float_type, [None, None]))\n    def predict_f_full_cov(self, Xnew):\n        \"\"\"\n        Compute the mean and covariance matrix of the latent function(s) at the\n        points Xnew.\n        \"\"\"\n        return self._build_predict(Xnew, full_cov=True)\n\n    @autoflow((settings.float_type, [None, None]), (tf.int32, []))\n    def predict_f_samples(self, Xnew, num_samples):\n        \"\"\"\n        Produce samples from the posterior latent function(s) at the points\n        Xnew.\n        \"\"\"\n        mu, var = self._build_predict(Xnew, full_cov=True)  # N x P, # P x N x N\n        jitter = tf.eye(tf.shape(mu)[0], dtype=settings.float_type) * settings.jitter\n        samples = []\n        for i in range(self.num_latent):\n            L = tf.cholesky(var[i, :, :] + jitter)\n            shape = tf.stack([tf.shape(L)[0], num_samples])\n            V = tf.random_normal(shape, dtype=settings.float_type)\n            samples.append(mu[:, i:i + 1] + tf.matmul(L, V))\n        return tf.transpose(tf.stack(samples))\n\n    @autoflow((settings.float_type, [None, None]))\n    def predict_y(self, Xnew):\n        \"\"\"\n        Compute the mean and variance of held-out data at the points Xnew\n        \"\"\"\n        pred_f_mean, pred_f_var = self._build_predict(Xnew)\n        return self.likelihood.predict_mean_and_var(pred_f_mean, pred_f_var)\n\n    @autoflow((settings.float_type, [None, None]), (settings.float_type, [None, None]))\n    def predict_density(self, Xnew, Ynew):\n        \"\"\"\n        Compute the (log) density of the data Ynew at the points Xnew\n\n        Note that this computes the log density of the data individually,\n        ignoring correlations between them. The result is a matrix the same\n        shape as Ynew containing the log densities.\n        \"\"\"\n        pred_f_mean, pred_f_var = self._build_predict(Xnew)\n        return self.likelihood.predict_density(pred_f_mean, pred_f_var, Ynew)\n\n    @abc.abstractmethod\n    def _build_predict(self, *args, **kwargs):\n        pass\n", "path": "gpflow/models/model.py"}]}