def test_predict():
    npr.seed(1)

    N = 10
    Npend = 3
    Ntest = 2
    D = 5

    gp = GPClassifier(D, burnin=5, num_fantasies=7)
    pred = npr.rand(Ntest, D)

    # Test with 0 points
    mu, v = gp.predict(pred)
    np.testing.assert_allclose(mu, 0, rtol=1e-7, atol=0, err_msg='', verbose=True)
    np.testing.assert_allclose(v, 1 + 1e-6, rtol=1e-7, atol=0, err_msg='', verbose=True)

    # Test with 1 point
    X = np.zeros((1, D))
    W = npr.randn(D, 1)
    val = X.dot(W).flatten() > 0

    gp.fit(X, val, fit_hypers=False)

    mu, v = gp.predict(pred)

    # Points closer to the origin will have less variance and a larger mean   
    mu, v = gp.predict(np.tile(np.linspace(0, 1, 100)[:, None], (1, D)))
    assert np.all(np.diff(mu) > 0) and np.all(np.diff(v) > 0)

    # Now let's make sure it doesn't break with more data and pending
    inputs = 0.5 * npr.rand(N, D)
    vals = inputs.dot(W).flatten() > 0
    pending = npr.rand(Npend, D)

    gp.fit(inputs, vals, pending)

    mu, v = gp.predict(pred)

    # Now let's check the gradients
    eps = 1e-5

    mu, v, dmu, dv = gp.predict(pred, compute_grad=True)

    # The implied loss is np.sum(mu**2) + np.sum(v**2)
    dloss = 2 * (dmu * mu[:, np.newaxis, :]).sum(2) + 2 * (v[:, np.newaxis, np.newaxis] * dv).sum(2)

    dloss_est = np.zeros(dloss.shape)
    for i in range(Ntest):
        for j in range(D):
            pred[i, j] += eps
            mu, v = gp.predict(pred)
            loss_1 = np.sum(mu ** 2) + np.sum(v ** 2)
            pred[i, j] -= 2 * eps
            mu, v = gp.predict(pred)
            loss_2 = np.sum(mu ** 2) + np.sum(v ** 2)
            pred[i, j] += eps
            dloss_est[i, j] = ((loss_1 - loss_2) / (2 * eps))

    assert np.linalg.norm(dloss - dloss_est) < 1e-5
def test_predict():
    npr.seed(1)

    N     = 10
    Npend = 3
    Ntest = 2
    D     = 5

    gp   = GPClassifier(D, burnin=5, num_fantasies=7)
    pred = npr.rand(Ntest,D)

    # Test with 0 points
    mu, v = gp.predict(pred)
    np.testing.assert_allclose(mu, 0, rtol=1e-7, atol=0, err_msg='', verbose=True)
    np.testing.assert_allclose(v, 1+1e-6, rtol=1e-7, atol=0, err_msg='', verbose=True)

    #Test with 1 point
    X   = np.zeros((1,D))
    W   = npr.randn(D,1)
    val = X.dot(W).flatten() > 0

    gp.fit(X, val, fit_hypers=False)

    mu, v = gp.predict(pred)
    
    # Points closer to the origin will have less variance and a larger mean   
    mu, v = gp.predict(np.tile(np.linspace(0,1,100)[:,None],(1,D)))
    assert np.all(np.diff(mu) > 0) and np.all(np.diff(v) > 0)

    # Now let's make sure it doesn't break with more data and pending
    inputs  = 0.5*npr.rand(N,D)
    vals    = inputs.dot(W).flatten() > 0
    pending = npr.rand(Npend,D)

    gp.fit(inputs, vals, pending)

    mu, v = gp.predict(pred)

    # Now let's check the gradients
    eps = 1e-5

    mu, v, dmu, dv = gp.predict(pred, compute_grad=True)

    # The implied loss is np.sum(mu**2) + np.sum(v**2)
    dloss = 2*(dmu*mu[:,np.newaxis,:]).sum(2) + 2*(v[:,np.newaxis,np.newaxis]*dv).sum(2)

    dloss_est = np.zeros(dloss.shape)
    for i in xrange(Ntest):
        for j in xrange(D):
            pred[i,j] += eps
            mu, v = gp.predict(pred)
            loss_1 = np.sum(mu**2) + np.sum(v**2)
            pred[i,j] -= 2*eps
            mu, v = gp.predict(pred)
            loss_2 = np.sum(mu**2) + np.sum(v**2)
            pred[i,j] += eps
            dloss_est[i,j] = ((loss_1 - loss_2) / (2*eps))

    assert np.linalg.norm(dloss - dloss_est) < 1e-5