Filtering step of Kalman filter: array version. 

    Parameters
    ----------
    G:  (dy, dx) numpy array
        mean of Y_t | X_t is G * X_t
    covX: (dx, dx) numpy array 
        covariance of Y_t | X_t
    pred: MeanAndCov object
        predictive distribution at time t

    Returns
    -------
    pred: MeanAndCov object
        filtering distribution at time t
    logpyt: float
        log density of Y_t | Y_{0:t-1}

    Note
    ----
    This performs the filtering step for N distinctive predictive means: 
    filt.mean should be a (N, dx) or (N) array; pred.mean in the output
    will have the same shape.

def filter_step_asarray(G, covY, pred, yt):
    """Filtering step of Kalman filter: array version. 

    Parameters
    ----------
    G:  (dy, dx) numpy array
        mean of Y_t | X_t is G * X_t
    covX: (dx, dx) numpy array 
        covariance of Y_t | X_t
    pred: MeanAndCov object
        predictive distribution at time t

    Returns
    -------
    pred: MeanAndCov object
        filtering distribution at time t
    logpyt: float
        log density of Y_t | Y_{0:t-1}

    Note
    ----
    This performs the filtering step for N distinctive predictive means: 
    filt.mean should be a (N, dx) or (N) array; pred.mean in the output
    will have the same shape. 
    
    """
    pm = pred.mean[:, np.newaxis] if pred.mean.ndim == 1 else pred.mean
    new_pred = MeanAndCov(mean=pm, cov=pred.cov)
    filt, logpyt = filter_step(G, covY, new_pred, yt)
    if pred.mean.ndim == 1:
        filt.mean.squeeze()
    return filt, logpyt