def vis_gauss_lanczos_mtx_size(): n_repetitions = 30 eig_max = 5 mtx_sizes = list(range(2, 45)) average_errs = [] for mtx_size in mtx_sizes: np.random.seed(0) average_err = 0 for seed in range(n_repetitions): mtx = rand_positive_definite_mtx(size=mtx_size, seed=seed, eig_max=eig_max).mtx tr_appr = tr_approx(mtx=mtx, f=matrix_fun, n_samples=mtx_size // 2 + 1, seed=seed, approx_method=ApproxMethod.gauss_lanczos_naive, max_iter=mtx_size // 2 + 1) tr_precise = np.trace(matrix_fun(mtx)) print("trace (approx): {}".format(tr_appr)) print("trace (precise): {}".format(tr_precise)) average_err += np.abs((tr_appr - tr_precise) / tr_appr) average_err /= n_repetitions average_errs.append(average_err) plt.figure() plt.plot(mtx_sizes, average_errs) plt.title( "Trace approximation with Gauss-Lanczos procedure: \n relative deviation" ) plt.xlabel("matrix size") plt.ylabel("average relative error per {} runs".format(n_repetitions)) plt.show()
def trace_approx_benchmark(n_lanczos_iter: int, n_hutchinson_iter: int, eig_max: int, fig_file: Path): methods = ( ApproxMethod.gauss_lanczos_naive, ApproxMethod.gauss_lanczos_memopt, ) n_repeats = 100 mtx_sizes = list(range(20, 121, 20)) n_observ = len(mtx_sizes) times_exact = [0] * n_observ times, errs = ({method: [0] * n_observ for method in methods} for _ in range(2)) for i_obs, m_size in enumerate(mtx_sizes): for seed in range(n_repeats): r_mtx = rand_positive_definite_mtx(size=m_size, seed=seed, eig_max=eig_max) t_exact_start = time.perf_counter() tr_exact = np.trace(matrix_fun(r_mtx.mtx)) t_exact_end = time.perf_counter() times_exact[i_obs] += t_exact_end - t_exact_start for method in methods: t_start = time.perf_counter() tr_appr = tr_approx(mtx=r_mtx.mtx, f=matrix_fun, n_samples=n_hutchinson_iter, max_iter=n_lanczos_iter, seed=seed, approx_method=method) t_end = time.perf_counter() times[method][i_obs] += t_end - t_start errs[method][i_obs] += np.abs((tr_appr - tr_exact) / tr_exact) def normalize(arr: List[int]): arr[i_obs] /= n_repeats map(normalize, [times_exact, *times.values(), *errs.values()]) fig, (ax_top, ax_bottom) = plt.subplots(nrows=2, ncols=1) ax_top.plot(mtx_sizes, times_exact) for method in methods: ax_top.plot(mtx_sizes, times[method]) ax_top.legend(["exact", *(str(method) for method in methods)]) ax_top.set_title("time performance in seconds") ax_top.set_xlabel("mtx size") for method in methods: ax_bottom.plot(mtx_sizes, errs[method]) ax_bottom.legend(list(map(str, methods))) ax_bottom.set_title("relative error") ax_bottom.set_xlabel("mtx size") plt.tight_layout() plt.savefig(fig_file)
def test_lanczos_vectorized(): mtx_size, seed = 10, 0 abs_tol = .1 for mtx_size in range(10, 40, 5): rand_mtx_props = rand_positive_definite_mtx(size=mtx_size, seed=seed, eig_max=5) q1, max_iter = rand_unit_vector(size=mtx_size, seed=seed).reshape((mtx_size, 1)), mtx_size // 2 + 1 res_vec = lanczos_memoptimized(a=rand_mtx_props.mtx, q1=q1, max_iter=max_iter) assert np.abs(np.max(res_vec.eigvals) - np.max(rand_mtx_props.eigvals)) < abs_tol
def test_lanczos_naive(): eig_max = 10 for mtx_size in (5, 10, 15, 20, 25, 30): rand_mtx_props = rand_positive_definite_mtx(mtx_size, seed=0, eig_max=eig_max) np.random.seed(0) q = rand_unit_vector(size=mtx_size, seed=0) eig_estimate = lanczos_naive(a=rand_mtx_props.mtx, q1=q.reshape((len(q), 1)), max_iter=mtx_size // 2 + 1) assert (0 <= eig_estimate.eigvals).all() and (eig_estimate.eigvals <= eig_max).all() print("test for n={} passed, k={}, deviation of max eig ={}" .format(mtx_size, len(eig_estimate.eigvals), np.abs(np.max(rand_mtx_props.eigvals) - np.max(eig_estimate.eigvals))))
def test_gauss_lanzcos(): mtx = rand_positive_definite_mtx(5, 0).mtx def f(x: np.ndarray) -> np.ndarray: return x**2 tr_appr = tr_approx(mtx=mtx, f=f, n_samples=3, seed=0, approx_method=ApproxMethod.bruteforce) assert np.abs((tr_appr - np.trace(f(mtx))) / tr_appr) < .5
def test_hutchinson_trick(): m = rand_positive_definite_mtx(10, 0).mtx def f(x: np.array) -> np.array: return np.log(np.abs(x) + .5) trace_precise = np.trace(f(m)) residuals = [ np.abs( tr_approx(m, f, n_samples, 0, ApproxMethod.bruteforce) - trace_precise) for n_samples in range(1, 20) ] assert np.median(residuals[:5]) > np.median(residuals[-5:])
def average_deviation(n_samples: int, eig_max: float, absolute: bool, mtx_size: int, method: ApproxMethod, max_iter: int) -> float: n_sample_runs = 15 result = 0 for seed in range(n_sample_runs): mtx = rand_positive_definite_mtx(size=mtx_size, seed=seed, eig_max=eig_max).mtx tr_precise = np.trace(matrix_fun(mtx)) delta_tr = np.abs(tr_precise - tr_approx(mtx=mtx, f=matrix_fun, n_samples=n_samples, seed=seed, approx_method=method, max_iter=max_iter)) if not absolute: delta_tr /= np.abs(tr_precise) result += delta_tr return result / n_sample_runs
def test_rand_matrix(): matrices: List[np.ndarray] = [] size = 2 max_eig = 20 out_file_stem = "rand_matrices" for seed in range(200): matrices.append(rand_positive_definite_mtx(size=size, seed=seed, eig_max=max_eig).mtx) matrices_flat = np.array([mtx.flatten() for mtx in matrices]) fig = plt.figure() ax = fig.add_subplot(projection="3d") ax.scatter(matrices_flat[:, 0], matrices_flat[:, 1], matrices_flat[:, 3], c=matrices_flat[:, 2]) ax.set_xlabel("a[0,0]") ax.set_ylabel("a[0,1]") ax.set_zlabel("a[1,1]") plt.savefig(out_file_stem + ".png") px_fig = px.scatter_3d(x=matrices_flat[:, 0], y=matrices_flat[:, 1], z=matrices_flat[:, 3], color=matrices_flat[:, 2]) with open(out_file_stem + ".html", "w") as fout: fout.write(px_fig.to_html())
def test_rand_positive_definite(): for seed in range(10): assert np.all( np.linalg.eigvals(rand_positive_definite_mtx(10, seed).mtx) > 0)