'Update the variational distributions for the precisions'

def _update_precisions(self, X, z):

    n_features = X.shape[1]
    if (self.covariance_type == 'spherical'):
        self.dof_ = ((0.5 * n_features) * np.sum(z, axis=0))
        for k in range(self.n_components):
            sq_diff = np.sum(((X - self.means_[k]) ** 2), axis=1)
            self.scale_[k] = 1.0
            self.scale_[k] += (0.5 * np.sum((z.T[k] * (sq_diff + n_features))))
            self.bound_prec_[k] = ((0.5 * n_features) * (digamma(self.dof_[k]) - np.log(self.scale_[k])))
        self.precs_ = np.tile((self.dof_ / self.scale_), [n_features, 1]).T
    elif (self.covariance_type == 'diag'):
        for k in range(self.n_components):
            self.dof_[k].fill((1.0 + (0.5 * np.sum(z.T[k], axis=0))))
            sq_diff = ((X - self.means_[k]) ** 2)
            self.scale_[k] = (np.ones(n_features) + (0.5 * np.dot(z.T[k], (sq_diff + 1))))
            self.precs_[k] = (self.dof_[k] / self.scale_[k])
            self.bound_prec_[k] = (0.5 * np.sum((digamma(self.dof_[k]) - np.log(self.scale_[k]))))
            self.bound_prec_[k] -= (0.5 * np.sum(self.precs_[k]))
    elif (self.covariance_type == 'tied'):
        self.dof_ = ((2 + X.shape[0]) + n_features)
        self.scale_ = ((X.shape[0] + 1) * np.identity(n_features))
        for k in range(self.n_components):
            diff = (X - self.means_[k])
            self.scale_ += np.dot(diff.T, (z[:, k:(k + 1)] * diff))
        self.scale_ = pinvh(self.scale_)
        self.precs_ = (self.dof_ * self.scale_)
        self.det_scale_ = linalg.det(self.scale_)
        self.bound_prec_ = (0.5 * wishart_log_det(self.dof_, self.scale_, self.det_scale_, n_features))
        self.bound_prec_ -= ((0.5 * self.dof_) * np.trace(self.scale_))
    elif (self.covariance_type == 'full'):
        for k in range(self.n_components):
            sum_resp = np.sum(z.T[k])
            self.dof_[k] = ((2 + sum_resp) + n_features)
            self.scale_[k] = ((sum_resp + 1) * np.identity(n_features))
            diff = (X - self.means_[k])
            self.scale_[k] += np.dot(diff.T, (z[:, k:(k + 1)] * diff))
            self.scale_[k] = pinvh(self.scale_[k])
            self.precs_[k] = (self.dof_[k] * self.scale_[k])
            self.det_scale_[k] = linalg.det(self.scale_[k])
            self.bound_prec_[k] = (0.5 * wishart_log_det(self.dof_[k], self.scale_[k], self.det_scale_[k], n_features))
            self.bound_prec_[k] -= ((0.5 * self.dof_[k]) * np.trace(self.scale_[k]))
