def _K_compute_ode_eq(self, transpose=False): """Compute the cross covariances between latent exponentiated quadratic and observed ordinary differential equations. :param transpose: if set to false the exponentiated quadratic is on the rows of the matrix and is computed according to self._t, if set to true it is on the columns and is computed according to self._t2 (default=False). :type transpose: bool""" if self._t2 is not None: if transpose: t_eq = self._t[self._index == 0] t_ode = self._t2[self._index2 > 0] index_ode = self._index2[self._index2 > 0] - 1 else: t_eq = self._t2[self._index2 == 0] t_ode = self._t[self._index > 0] index_ode = self._index[self._index > 0] - 1 else: t_eq = self._t[self._index == 0] t_ode = self._t[self._index > 0] index_ode = self._index[self._index > 0] - 1 if t_ode.size == 0 or t_eq.size == 0: if transpose: self._K_eq_ode = np.zeros((t_eq.shape[0], t_ode.shape[0])) else: self._K_ode_eq = np.zeros((t_ode.shape[0], t_eq.shape[0])) return t_ode_mat = t_ode[:, None] t_eq_mat = t_eq[None, :] if self.delay is not None: t_ode_mat -= self.delay[index_ode, None] diff_t = (t_ode_mat - t_eq_mat) inv_sigma_diff_t = 1. / self.sigma * diff_t decay_vals = self.decay[index_ode][:, None] half_sigma_d_i = 0.5 * self.sigma * decay_vals if self.is_stationary: ln_part, signs = ln_diff_erfs(inf, half_sigma_d_i - inv_sigma_diff_t, return_sign=True) else: ln_part, signs = ln_diff_erfs(half_sigma_d_i + t_eq_mat / self.sigma, half_sigma_d_i - inv_sigma_diff_t, return_sign=True) sK = signs * np.exp(half_sigma_d_i * half_sigma_d_i - decay_vals * diff_t + ln_part) sK *= 0.5 if not self.is_normalized: sK *= np.sqrt(np.pi) * self.sigma if transpose: self._K_eq_ode = sK.T else: self._K_ode_eq = sK
def _K_compute_ode_eq(self, transpose=False): """Compute the cross covariances between latent exponentiated quadratic and observed ordinary differential equations. :param transpose: if set to false the exponentiated quadratic is on the rows of the matrix and is computed according to self._t, if set to true it is on the columns and is computed according to self._t2 (default=False). :type transpose: bool""" if self._t2 is not None: if transpose: t_eq = self._t[self._index == 0] t_ode = self._t2[self._index2 > 0] index_ode = self._index2[self._index2 > 0] - 1 else: t_eq = self._t2[self._index2 == 0] t_ode = self._t[self._index > 0] index_ode = self._index[self._index > 0] - 1 else: t_eq = self._t[self._index == 0] t_ode = self._t[self._index > 0] index_ode = self._index[self._index > 0] - 1 if t_ode.size == 0 or t_eq.size == 0: if transpose: self._K_eq_ode = np.zeros((t_eq.shape[0], t_ode.shape[0])) else: self._K_ode_eq = np.zeros((t_ode.shape[0], t_eq.shape[0])) return t_ode_mat = t_ode[:, None] t_eq_mat = t_eq[None, :] if self.delay is not None: t_ode_mat -= self.delay[index_ode, None] diff_t = t_ode_mat - t_eq_mat inv_sigma_diff_t = 1.0 / self.sigma * diff_t decay_vals = self.decay[index_ode][:, None] half_sigma_d_i = 0.5 * self.sigma * decay_vals if self.is_stationary: ln_part, signs = ln_diff_erfs(inf, half_sigma_d_i - inv_sigma_diff_t, return_sign=True) else: ln_part, signs = ln_diff_erfs( half_sigma_d_i + t_eq_mat / self.sigma, half_sigma_d_i - inv_sigma_diff_t, return_sign=True ) sK = signs * np.exp(half_sigma_d_i * half_sigma_d_i - decay_vals * diff_t + ln_part) sK *= 0.5 if not self.is_normalized: sK *= np.sqrt(np.pi) * self.sigma if transpose: self._K_eq_ode = sK.T else: self._K_ode_eq = sK
def _compute_H(self, t, index, t2, index2, update_derivatives=False, stationary=False): """Helper function for computing part of the ode1 covariance function. :param t: first time input. :type t: array :param index: Indices of first output. :type index: array of int :param t2: second time input. :type t2: array :param index2: Indices of second output. :type index2: array of int :param update_derivatives: whether to update derivatives (default is False) :return h : result of this subcomponent of the kernel for the given values. :rtype: ndarray """ if stationary: raise NotImplementedError, "Error, stationary version of this covariance not yet implemented." # Vector of decays and delays associated with each output. Decay = self.decay[index] Decay2 = self.decay[index2] t_mat = t[:, None] t2_mat = t2[None, :] if self.delay is not None: Delay = self.delay[index] Delay2 = self.delay[index2] t_mat -= Delay[:, None] t2_mat -= Delay2[None, :] diff_t = (t_mat - t2_mat) inv_sigma_diff_t = 1. / self.sigma * diff_t half_sigma_decay_i = 0.5 * self.sigma * Decay[:, None] ln_part_1, sign1 = ln_diff_erfs(half_sigma_decay_i + t2_mat / self.sigma, half_sigma_decay_i - inv_sigma_diff_t, return_sign=True) ln_part_2, sign2 = ln_diff_erfs(half_sigma_decay_i, half_sigma_decay_i - t_mat / self.sigma, return_sign=True) h = sign1 * np.exp(half_sigma_decay_i * half_sigma_decay_i - Decay[:, None] * diff_t + ln_part_1 - np.log(Decay[:, None] + Decay2[None, :])) h -= sign2 * np.exp(half_sigma_decay_i * half_sigma_decay_i - Decay[:, None] * t_mat - Decay2[None, :] * t2_mat + ln_part_2 - np.log(Decay[:, None] + Decay2[None, :])) if update_derivatives: sigma2 = self.sigma * self.sigma # Update ith decay gradient dh_ddecay = ( (0.5 * Decay[:, None] * sigma2 * (Decay[:, None] + Decay2[None, :]) - 1) * h + (-diff_t * sign1 * np.exp(half_sigma_decay_i * half_sigma_decay_i - Decay[:, None] * diff_t + ln_part_1) + t_mat * sign2 * np.exp(half_sigma_decay_i * half_sigma_decay_i - Decay[:, None] * t_mat - Decay2 * t2_mat + ln_part_2)) + self.sigma / np.sqrt(np.pi) * (-np.exp(-diff_t * diff_t / sigma2) + np.exp(-t2_mat * t2_mat / sigma2 - Decay[:, None] * t_mat) + np.exp(-t_mat * t_mat / sigma2 - Decay2[None, :] * t2_mat) - np.exp(-(Decay[:, None] * t_mat + Decay2[None, :] * t2_mat)))) self._dh_ddecay = (dh_ddecay / (Decay[:, None] + Decay2[None, :])).real # Update jth decay gradient dh_ddecay2 = ( t2_mat * sign2 * np.exp(half_sigma_decay_i * half_sigma_decay_i - (Decay[:, None] * t_mat + Decay2[None, :] * t2_mat) + ln_part_2) - h) self._dh_ddecay2 = (dh_ddecay / (Decay[:, None] + Decay2[None, :])).real # Update sigma gradient self._dh_dsigma = ( half_sigma_decay_i * Decay[:, None] * h + 2 / (np.sqrt(np.pi) * (Decay[:, None] + Decay2[None, :])) * ((-diff_t / sigma2 - Decay[:, None] / 2) * np.exp(-diff_t * diff_t / sigma2) + (-t2_mat / sigma2 + Decay[:, None] / 2) * np.exp(-t2_mat * t2_mat / sigma2 - Decay[:, None] * t_mat) - (-t_mat / sigma2 - Decay[:, None] / 2) * np.exp(-t_mat * t_mat / sigma2 - Decay2[None, :] * t2_mat) - Decay[:, None] / 2 * np.exp(-(Decay[:, None] * t_mat + Decay2[None, :] * t2_mat)))) return h
def _compute_H(self, t, index, t2, index2, update_derivatives=False, stationary=False): """Helper function for computing part of the ode1 covariance function. :param t: first time input. :type t: array :param index: Indices of first output. :type index: array of int :param t2: second time input. :type t2: array :param index2: Indices of second output. :type index2: array of int :param update_derivatives: whether to update derivatives (default is False) :return h : result of this subcomponent of the kernel for the given values. :rtype: ndarray """ if stationary: raise NotImplementedError, "Error, stationary version of this covariance not yet implemented." # Vector of decays and delays associated with each output. Decay = self.decay[index] Decay2 = self.decay[index2] t_mat = t[:, None] t2_mat = t2[None, :] if self.delay is not None: Delay = self.delay[index] Delay2 = self.delay[index2] t_mat -= Delay[:, None] t2_mat -= Delay2[None, :] diff_t = t_mat - t2_mat inv_sigma_diff_t = 1.0 / self.sigma * diff_t half_sigma_decay_i = 0.5 * self.sigma * Decay[:, None] ln_part_1, sign1 = ln_diff_erfs( half_sigma_decay_i + t2_mat / self.sigma, half_sigma_decay_i - inv_sigma_diff_t, return_sign=True ) ln_part_2, sign2 = ln_diff_erfs(half_sigma_decay_i, half_sigma_decay_i - t_mat / self.sigma, return_sign=True) h = sign1 * np.exp( half_sigma_decay_i * half_sigma_decay_i - Decay[:, None] * diff_t + ln_part_1 - np.log(Decay[:, None] + Decay2[None, :]) ) h -= sign2 * np.exp( half_sigma_decay_i * half_sigma_decay_i - Decay[:, None] * t_mat - Decay2[None, :] * t2_mat + ln_part_2 - np.log(Decay[:, None] + Decay2[None, :]) ) if update_derivatives: sigma2 = self.sigma * self.sigma # Update ith decay gradient dh_ddecay = ( (0.5 * Decay[:, None] * sigma2 * (Decay[:, None] + Decay2[None, :]) - 1) * h + ( -diff_t * sign1 * np.exp(half_sigma_decay_i * half_sigma_decay_i - Decay[:, None] * diff_t + ln_part_1) + t_mat * sign2 * np.exp( half_sigma_decay_i * half_sigma_decay_i - Decay[:, None] * t_mat - Decay2 * t2_mat + ln_part_2 ) ) + self.sigma / np.sqrt(np.pi) * ( -np.exp(-diff_t * diff_t / sigma2) + np.exp(-t2_mat * t2_mat / sigma2 - Decay[:, None] * t_mat) + np.exp(-t_mat * t_mat / sigma2 - Decay2[None, :] * t2_mat) - np.exp(-(Decay[:, None] * t_mat + Decay2[None, :] * t2_mat)) ) ) self._dh_ddecay = (dh_ddecay / (Decay[:, None] + Decay2[None, :])).real # Update jth decay gradient dh_ddecay2 = ( t2_mat * sign2 * np.exp( half_sigma_decay_i * half_sigma_decay_i - (Decay[:, None] * t_mat + Decay2[None, :] * t2_mat) + ln_part_2 ) - h ) self._dh_ddecay2 = (dh_ddecay / (Decay[:, None] + Decay2[None, :])).real # Update sigma gradient self._dh_dsigma = half_sigma_decay_i * Decay[:, None] * h + 2 / ( np.sqrt(np.pi) * (Decay[:, None] + Decay2[None, :]) ) * ( (-diff_t / sigma2 - Decay[:, None] / 2) * np.exp(-diff_t * diff_t / sigma2) + (-t2_mat / sigma2 + Decay[:, None] / 2) * np.exp(-t2_mat * t2_mat / sigma2 - Decay[:, None] * t_mat) - (-t_mat / sigma2 - Decay[:, None] / 2) * np.exp(-t_mat * t_mat / sigma2 - Decay2[None, :] * t2_mat) - Decay[:, None] / 2 * np.exp(-(Decay[:, None] * t_mat + Decay2[None, :] * t2_mat)) ) return h