Esempio n. 1
0
    def test_posterior_mean_CG_equivalency(self):
        """
        The probabilistic linear solver(s) should recover CG iterates as a posterior mean for specific
        covariances.
        """

        # Linear system
        A, b = self.poisson_linear_system

        # Callback function to return CG iterates
        cg_iterates = []

        def callback_iterates_CG(xk):
            cg_iterates.append(
                np.eye(np.shape(A)[0]) @ xk
            )  # identity hack to actually save different iterations

        # Solve linear system

        # Initial guess as chosen by PLS: x0 = Ainv.mean @ b
        x0 = b

        # Conjugate gradient method
        xhat_cg, info_cg = scipy.sparse.linalg.cg(
            A=A, b=b, x0=x0, tol=10 ** -6, callback=callback_iterates_CG
        )
        cg_iters_arr = np.array([x0] + cg_iterates)

        # Matrix priors (encoding weak symmetric posterior correspondence)
        Ainv0 = rvs.Normal(
            mean=linops.Identity(A.shape[1]),
            cov=linops.SymmetricKronecker(A=linops.Identity(A.shape[1])),
        )
        A0 = rvs.Normal(
            mean=linops.Identity(A.shape[1]), cov=linops.SymmetricKronecker(A)
        )
        for kwargs in [{"assume_A": "sympos", "rtol": 10 ** -6}]:
            with self.subTest():
                # Define callback function to obtain search directions
                pls_iterates = []

                # pylint: disable=cell-var-from-loop
                def callback_iterates_PLS(
                    xk, Ak, Ainvk, sk, yk, alphak, resid, **kwargs
                ):
                    pls_iterates.append(xk.mean)

                # Probabilistic linear solver
                xhat_pls, _, _, info_pls = linalg.problinsolve(
                    A=A,
                    b=b,
                    Ainv0=Ainv0,
                    A0=A0,
                    callback=callback_iterates_PLS,
                    **kwargs
                )
                pls_iters_arr = np.array([x0] + pls_iterates)

                self.assertAllClose(xhat_pls.mean, xhat_cg, rtol=10 ** -12)
                self.assertAllClose(pls_iters_arr, cg_iters_arr, rtol=10 ** -12)
Esempio n. 2
0
    def test_iterative_covariance_trace_update(self):
        """The solver's returned value for the trace must match the actual trace of the solution covariance."""
        A, b, x_true = self.rbf_kernel_linear_system

        for calib_method in [None, 0, 1.0, "adhoc", "weightedmean", "gpkern"]:
            with self.subTest():
                x_est, Ahat, Ainvhat, info = linalg.problinsolve(
                    A=A, b=b, calibration=calib_method)
                self.assertAlmostEqual(
                    info["trace_sol_cov"],
                    x_est.cov.trace(),
                    msg=
                    "Iteratively computed trace not equal to trace of solution covariance.",
                )
Esempio n. 3
0
    def test_uncertainty_calibration_error(self):
        """Test if the available uncertainty calibration procedures affect the error of the returned solution."""
        tol = 10**-6
        A, b, x_true = self.rbf_kernel_linear_system

        for calib_method in [None, 0, "adhoc", "weightedmean", "gpkern"]:
            with self.subTest():
                x_est, Ahat, Ainvhat, info = linalg.problinsolve(
                    A=A, b=b, calibration=calib_method)
                self.assertLessEqual(
                    (x_true - x_est.mean).T @ A @ (x_true - x_est.mean),
                    tol,
                    msg=
                    "Estimated solution not sufficiently close to true solution.",
                )
Esempio n. 4
0
    def test_posterior_uncertainty_zero_in_explored_space(self):
        """
        Test whether the posterior uncertainty over the matrices A and Ainv is zero in the already explored spaces
        span(S) and span(Y).
        """
        A, b, x_true = self.rbf_kernel_linear_system
        n = A.shape[0]

        for calibrate in [False, 0.0]:  # , 10 ** -6, 2.8]:
            # TODO (probnum#100) expand this test to the prior covariance class
            # admitting calibration
            with self.subTest():
                # Define callback function to obtain search directions
                S = []  # search directions
                Y = []  # observations

                # pylint: disable=cell-var-from-loop
                def callback_postparams(xk, Ak, Ainvk, sk, yk, alphak, resid):
                    S.append(sk)
                    Y.append(yk)

                # Solve linear system
                u_solver, Ahat, Ainvhat, info = linalg.problinsolve(
                    A=A,
                    b=b,
                    assume_A="sympos",
                    callback=callback_postparams,
                    calibration=calibrate,
                )
                # Create arrays from lists
                S = np.squeeze(np.array(S)).T
                Y = np.squeeze(np.array(Y)).T

                self.assertAllClose(
                    Ahat.cov.A @ S,
                    np.zeros_like(S),
                    atol=1e-6,
                    msg=
                    "Uncertainty over A in explored space span(S) not zero.",
                )
                self.assertAllClose(
                    Ainvhat.cov.A @ Y,
                    np.zeros_like(S),
                    atol=1e-6,
                    msg=
                    "Uncertainty over Ainv in explored space span(Y) not zero.",
                )