def test_smoke_test(self): np.random.seed(0) n = 2 p = 1 T = 1000 lam = 1e-5 A_true = np.array([ [1., 1.], [0, 1.], ]) C_true = np.array([[1., 1.]]) W_true = .01 * np.eye(n) V_true = .1 * np.eye(p) # Get trajectory x = [npr.randn(n)] y = [ C_true @ x[0] + np.random.multivariate_normal(np.zeros(p), V_true) ] for t in range(T - 1): xt = x[-1] x.append(A_true @ xt + np.random.multivariate_normal(np.zeros(n), W_true)) y.append(C_true @ xt + np.random.multivariate_normal(np.zeros(p), V_true)) x = np.array(x) y = np.array(y) K = np.ones((T, p), dtype=np.bool) W_neg_sqrt_true = sqrtm(np.linalg.inv(W_true)) V_neg_sqrt_true = sqrtm(np.linalg.inv(V_true)) def prox(params, t): return auto_ks.KalmanSmootherParameters(params.A, params.W_neg_sqrt, params.C, params.V_neg_sqrt), 0.0 params = auto_ks.KalmanSmootherParameters( A_true + 1e-2 * np.random.randn(n, n), W_neg_sqrt_true, C_true, V_neg_sqrt_true + .1 * np.eye(p)) params, info = auto_ks.tune(params, prox, y, K, lam, verbose=True, niter=25, lr=1e-3) np.testing.assert_array_less(np.diff(info["losses"]), 0.0)
def prox(params, t): r = 0.0 W_neg_sqrt = params.W_neg_sqrt / (t * alpha + 1.0) idx = np.arange(W_neg_sqrt.shape[0]) W_neg_sqrt[idx, idx] = 0.0 r += alpha * np.sum(np.square(W_neg_sqrt)) W_neg_sqrt[idx, idx] = np.diag(params.W_neg_sqrt) V_neg_sqrt = params.V_neg_sqrt / (t * alpha + 1.0) idx = np.arange(V_neg_sqrt.shape[0]) V_neg_sqrt[idx, idx] = 0.0 r += alpha * np.sum(np.square(V_neg_sqrt)) V_neg_sqrt[idx, idx] = np.diag(params.V_neg_sqrt) return auto_ks.KalmanSmootherParameters(A, W_neg_sqrt, C, V_neg_sqrt), r
def test_kalman_filter_vs_cvxpy(self): np.random.seed(0) n = 3 p = 6 T = 10 lam = 1e-10 for _ in range(5): A = npr.randn(n, n) W_neg_sqrt = npr.randn(n, n) C = npr.randn(p, n) V_neg_sqrt = npr.randn(p, p) y = npr.randn(T, p) K = np.zeros(T * p, dtype=int) K[:int(.7 * T * p)] = 1 np.random.shuffle(K) K = K.astype(bool).reshape((T, p)) params = auto_ks.KalmanSmootherParameters(A, W_neg_sqrt, C, V_neg_sqrt) xhat, yhat, DT = auto_ks.kalman_smoother(params, y, K, lam) xs = cp.Variable((T, n)) ys = cp.Variable((T, p)) objective = 0.0 for t in range(T): objective += cp.sum_squares(V_neg_sqrt @ (ys[t] - C @ xs[t])) if t < T - 1: objective += cp.sum_squares( W_neg_sqrt @ (xs[t + 1] - A @ xs[t])) objective += cp.sum_squares(lam * xs) + cp.sum_squares(lam * ys) constraints = [] rows, cols = K.nonzero() for t, i in zip(rows, cols): constraints += [ys[t, i] == y[t, i]] prob = cp.Problem(cp.Minimize(objective), constraints) prob.solve(solver='OSQP') np.testing.assert_allclose(xhat, xs.value) np.testing.assert_allclose(yhat, ys.value)
def test_kalman_filter_derivative(self): np.random.seed(0) n = 5 p = 10 T = 100 lam = 1e-10 for _ in range(10): A = npr.randn(n, n) W_neg_sqrt = np.eye(n) C = npr.randn(p, n) V_neg_sqrt = npr.randn(p, p) y = npr.randn(T, p) K = np.zeros(T * p, dtype=int) K[:int(.7 * T * p)] = 1 np.random.shuffle(K) K = K.astype(bool).reshape((T, p)) params = auto_ks.KalmanSmootherParameters(A, W_neg_sqrt, C, V_neg_sqrt) xhat, yhat, DT = auto_ks.kalman_smoother(params, y, K, lam) f = np.sum(xhat) + np.sum(yhat) dxhat = np.ones(xhat.shape) dyhat = np.ones(yhat.shape) derivatives = DT(dxhat, dyhat) eps = 1e-6 xhat_p, yhat_p, _ = auto_ks.kalman_smoother( params + eps * derivatives, y, K, lam) fp = np.sum(xhat_p) + np.sum(yhat_p) increase = fp - f dA = derivatives.DA dW_neg_sqrt = derivatives.DW_neg_sqrt dC = derivatives.DC dV_neg_sqrt = derivatives.DV_neg_sqrt predicted_increase = eps * ( np.sum(dA * dA) + np.sum(dW_neg_sqrt * dW_neg_sqrt) + np.sum(dC * dC) + np.sum(dV_neg_sqrt * dV_neg_sqrt)) np.testing.assert_allclose(predicted_increase, increase, atol=1e-5)
def prox(params, t): return auto_ks.KalmanSmootherParameters( np.maximum(params.A, 0), W_neg_sqrt, C, np.diag(np.maximum(np.diag(params.V_neg_sqrt), 0))), 0.0
df = pd.read_csv("data/state_pop_Annual.txt", delimiter="\t", parse_dates=["DATE"]) df.drop(["AKPOP", "HIPOP"], axis=1, inplace=True) columns = df.columns[1:] y = np.array(df.drop(["DATE"], axis=1)) / 1000.0 # construct initial parameters T, n = y.shape m = n lam = 1e-10 A = np.eye(n) W_neg_sqrt = np.sqrt(1. / .001) * np.diag(np.random.uniform(0.8, 1.2, size=n)) C = np.eye(m) V_neg_sqrt = np.sqrt(1. / .001) * np.diag(np.random.uniform(0.8, 1.2, size=n)) params = auto_ks.KalmanSmootherParameters(A, W_neg_sqrt, C, V_neg_sqrt) K = np.zeros(y.shape, dtype=bool) M = np.zeros(y.shape, dtype=bool) M_test = np.zeros(y.shape, dtype=bool) for t in range(T): idx = np.arange(n) np.random.shuffle(idx) indices = idx[:30] K[t, indices] = True np.random.shuffle(indices) M[t, indices[:12]] = True M_test[t, indices[12:12 + 5]] = True def prox(params, t):
y = np.random.multivariate_normal(C @ x, V) ys.append(y) ys = np.array(ys) x = np.zeros(n) ys_test = [] for _ in range(T): x = np.random.multivariate_normal(A @ x, W) y = np.random.multivariate_normal(C @ x, V) ys_test.append(y) ys_test = np.array(ys_test) parameters = auto_ks.KalmanSmootherParameters(np.random.randn(n, n), np.eye(n) * .5, np.random.randn(m, n), np.eye(m) * .5) def prox(params, t): return params, 0. def callback(k, yhat, parameters, prediction_loss_forecast): print("TEST", prediction_loss_forecast(parameters, ys_test)) parameters, info, prediction_loss_forecast = auto_ks.tune_forecast( parameters, prox, ys,
def prox(params, t): return auto_ks.KalmanSmootherParameters(params.A, params.W_neg_sqrt, params.C, params.V_neg_sqrt), 0.0
eye = np.eye(3) zeros = np.zeros((3, 3)) h = 1. / 100.0 lam = 1e-10 alpha = 1e-4 n = 9 m = 8 A = np.bmat([[eye, h * eye, zeros], [zeros, eye, h * eye], [zeros, zeros, eye]]) C = np.bmat([[eye, zeros, zeros], [zeros, zeros, eye], [np.zeros((2, 3)), np.eye(2), np.zeros((2, 4))]]) W_neg_sqrt = np.eye(n) V_neg_sqrt = .01 * np.eye(m) params_initial = auto_ks.KalmanSmootherParameters(np.array(A), np.array(W_neg_sqrt), np.array(C), np.array(V_neg_sqrt)) # proximal operator for r def prox(params, t): r = 0.0 W_neg_sqrt = params.W_neg_sqrt / (t * alpha + 1.0) idx = np.arange(W_neg_sqrt.shape[0]) W_neg_sqrt[idx, idx] = 0.0 r += alpha * np.sum(np.square(W_neg_sqrt)) W_neg_sqrt[idx, idx] = np.diag(params.W_neg_sqrt) V_neg_sqrt = params.V_neg_sqrt / (t * alpha + 1.0) idx = np.arange(V_neg_sqrt.shape[0]) V_neg_sqrt[idx, idx] = 0.0