def predictive_gradients(self, Xnew, kern=None):
if kern is None:<EOL><INDENT>kern = self.kern<EOL><DEDENT>mean_jac = np.empty((Xnew.shape[<NUM_LIT:0>], Xnew.shape[<NUM_LIT:1>], self.output_dim))<EOL>for i in range(self.output_dim):<EOL><INDENT>mean_jac[:, :, i] = kern.gradients_X(<EOL>self.posterior.woodbury_vector[:, i:i+<NUM_LIT:1>].T, Xnew,<EOL>self._predictive_variable)<EOL><DEDENT>dv_dX = kern.gradients_X_diag(np.ones(Xnew.shape[<NUM_LIT:0>]), Xnew)<EOL>if self.posterior.woodbury_inv.ndim == <NUM_LIT:3>:<EOL><INDENT>var_jac = np.empty(dv_dX.shape +<EOL>(self.posterior.woodbury_inv.shape[<NUM_LIT:2>],))<EOL>var_jac[:] = dv_dX[:, :, None]<EOL>for i in range(self.posterior.woodbury_inv.shape[<NUM_LIT:2>]):<EOL><INDENT>alpha = -<NUM_LIT>*np.dot(kern.K(Xnew, self._predictive_variable),<EOL>self.posterior.woodbury_inv[:, :, i])<EOL>var_jac[:, :, i] += kern.gradients_X(alpha, Xnew,<EOL>self._predictive_variable)<EOL><DEDENT><DEDENT>else:<EOL><INDENT>var_jac = dv_dX<EOL>alpha = -<NUM_LIT>*np.dot(kern.K(Xnew, self._predictive_variable),<EOL>self.posterior.woodbury_inv)<EOL>var_jac += kern.gradients_X(alpha, Xnew, self._predictive_variable)<EOL><DEDENT>return mean_jac, var_jac<EOL>
Compute the derivatives of the predicted latent function with respect
to X*

Given a set of points at which to predict X* (size [N*,Q]), compute the
derivatives of the mean and variance. Resulting arrays are sized:
    dmu_dX* -- [N*, Q ,D], where D is the number of output in this GP
    (usually one).

Note that this is not the same as computing the mean and variance of
the derivative of the function!

 dv_dX*  -- [N*, Q],    (since all outputs have the same variance)
:param X: The points at which to get the predictive gradients
:type X: np.ndarray (Xnew x self.input_dim)
:returns: dmu_dX, dv_dX
:rtype: [np.ndarray (N*, Q ,D), np.ndarray (N*,Q) ]