From 7c251d8ead897c4ee93e4e15060edd35342fbc8f Mon Sep 17 00:00:00 2001 From: William Jones Date: Mon, 10 Oct 2022 12:02:31 +0100 Subject: [PATCH] Further improved COVID model, completed initial automated COVID model test --- CMakeLists.txt | 2 +- doc/Doxyfile.in | 2 +- include/utility.hh | 4 +++ src/COVID/DEM_COVID.cc | 2 +- src/COVID/dynamic_COVID_model.cc | 28 ++++++++---------- src/utility.cc | 48 +++++++++++++++++++++++++++++++ tests/dynamic_COVID_model_test.cc | 7 ----- tests/utility_test.cc | 27 +++++++++++++++++ 8 files changed, 94 insertions(+), 26 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6fe0ec8..5dee83f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,7 +10,7 @@ cmake_minimum_required(VERSION 3.16) SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}-std=c++14 -O3 -flto -march=native\ - -D_GLIBCXX_PARALLEL") + -D_GLIBCXX_PARALLEL -DNDEBUG") SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS}-O3") SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS}-O3") diff --git a/doc/Doxyfile.in b/doc/Doxyfile.in index 15ed796..bbb5017 100644 --- a/doc/Doxyfile.in +++ b/doc/Doxyfile.in @@ -788,7 +788,7 @@ WARN_LOGFILE = # spaces. See also FILE_PATTERNS and EXTENSION_MAPPING # Note: If this tag is empty the current directory is searched. -INPUT = "./" "src" "include" +INPUT = "./" "src" "include" "include/COVID" "include/3body" "include/tests" "src/COVID" "src/3body" "tests" # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses diff --git a/include/utility.hh b/include/utility.hh index 3dd04d4..80099fa 100644 --- a/include/utility.hh +++ b/include/utility.hh @@ -34,6 +34,10 @@ Eigen::VectorXd rungekutta(std::function func, SparseMD permute_kron_matrix(const SparseMD& matrix, const Eigen::VectorXi& new_order, const Eigen::VectorXi& cur_order_size); + +SparseMD calc_permuted_kron_identity_product( + const int& id_size, const SparseMD& matrix, const Eigen::VectorXi& new_order, + const Eigen::VectorXi& cur_order_size); /* * Given a multidimensional matrix represented in block matrix form, give the * position in the block matrix from a multidimeional matrix coordinate diff --git a/src/COVID/DEM_COVID.cc b/src/COVID/DEM_COVID.cc index 76a204e..e44b576 100644 --- a/src/COVID/DEM_COVID.cc +++ b/src/COVID/DEM_COVID.cc @@ -59,7 +59,7 @@ int run_COVID_test() { COVID_model.select_response_vars = select_response_vars; COVID_model.num_response_vars = 2; COVID_model.response_vars = response_vars; - COVID_model.max_invert_it = 10; + COVID_model.max_invert_it = 128; COVID_model.invert_model(); if (STORE) { diff --git a/src/COVID/dynamic_COVID_model.cc b/src/COVID/dynamic_COVID_model.cc index 2530d6d..d0c4a26 100644 --- a/src/COVID/dynamic_COVID_model.cc +++ b/src/COVID/dynamic_COVID_model.cc @@ -255,13 +255,13 @@ SparseMD dynamic_COVID_model::calc_location_transition_matrix( ZERO(5, 5), ZERO(5, 5), ZERO(5, 5), ZERO(5, 5), loc_ards, ZERO(5, 5), ZERO(5, 5), ZERO(5, 5), ZERO(5, 5), loc_dec; - SparseMD loc_full = kroneckerProduct( - (Eigen::MatrixXd::Identity(20, 20)).sparseView(), loc_tmp.sparseView()); Eigen::VectorXi new_order = Eigen::VectorXi::Zero(4); new_order << 0, 2, 1, 3; Eigen::VectorXi sizes = Eigen::VectorXi::Zero(4); sizes << 5, 4, 5, 4; - loc_full = utility::permute_kron_matrix(loc_full, new_order, sizes); + + SparseMD loc_full = utility::calc_permuted_kron_identity_product( + 20, loc_tmp.sparseView(), new_order, sizes); // Change sizes to reflect new order sizes << 5, 5, 4, 4; @@ -373,15 +373,14 @@ SparseMD dynamic_COVID_model::calc_infection_transition_matrix( ZERO(5, 5), inf_remo, ZERO(5, 5), ZERO(5, 5), ZERO(5, 5), ZERO(5, 5), ZERO(5, 5), inf_iso; - SparseMD inf_full = kroneckerProduct( - (Eigen::MatrixXd::Identity(16, 16)).sparseView(), inf_tmp.sparseView()); - Eigen::VectorXi new_order = Eigen::VectorXi::Zero(4); new_order << 1, 0, 2, 3; Eigen::VectorXi sizes = Eigen::VectorXi::Zero(4); sizes << 5, 5, 4, 4; - inf_full = utility::permute_kron_matrix(inf_full, new_order, sizes); + + SparseMD inf_full = utility::calc_permuted_kron_identity_product( + 16, inf_tmp.sparseView(), new_order, sizes); return inf_full; } @@ -419,15 +418,13 @@ SparseMD dynamic_COVID_model::calc_clinical_transition_matrix( ZERO(4, 4), cli_abp, ZERO(4, 4), ZERO(4, 4), ZERO(4, 4), ZERO(4, 4), ZERO(4, 4), cli_abn; - SparseMD cli_full = - kroneckerProduct((Eigen::MatrixXd::Identity(20, 20)).sparseView(), - cli_tmp.sparseView()) - .eval(); Eigen::VectorXi new_order = Eigen::VectorXi::Zero(4); new_order << 2, 1, 0, 3; Eigen::VectorXi sizes = Eigen::VectorXi::Zero(4); sizes << 4, 5, 5, 4; - cli_full = utility::permute_kron_matrix(cli_full, new_order, sizes); + + SparseMD cli_full = utility::calc_permuted_kron_identity_product( + 20, cli_tmp.sparseView(), new_order, sizes); // Change sizes to reflect new order sizes << 5, 5, 4, 4; Eigen::VectorXi r_pos = Eigen::VectorXi::Zero(4); @@ -505,14 +502,13 @@ SparseMD dynamic_COVID_model::calc_testing_transition_matrix( ZERO(4, 4), test_abp, ZERO(4, 4), ZERO(4, 4), ZERO(4, 4), ZERO(4, 4), ZERO(4, 4), test_abn; - SparseMD test_full = kroneckerProduct( - (Eigen::MatrixXd::Identity(20, 20)).sparseView(), test_tmp.sparseView()); - Eigen::VectorXi new_order = Eigen::VectorXi::Zero(4); new_order << 2, 1, 3, 0; Eigen::VectorXi sizes = Eigen::VectorXi::Zero(4); sizes << 4, 5, 5, 4; - test_full = utility::permute_kron_matrix(test_full, new_order, sizes); + + SparseMD test_full = utility::calc_permuted_kron_identity_product( + 20, test_tmp.sparseView(), new_order, sizes); sizes << 5, 5, 4, 4; Eigen::VectorXi r_pos = Eigen::VectorXi::Zero(4); diff --git a/src/utility.cc b/src/utility.cc index c59cd62..f09052d 100644 --- a/src/utility.cc +++ b/src/utility.cc @@ -161,6 +161,54 @@ SparseMD utility::permute_kron_matrix(const SparseMD& matrix, return matrix2; } +SparseMD utility::calc_permuted_kron_identity_product( + const int& id_size, const SparseMD& matrix, + const Eigen::VectorXi& new_order, const Eigen::VectorXi& cur_order_size) { + Eigen::VectorXi pos_vector = Eigen::VectorXi::Ones(cur_order_size.size()); + Eigen::VectorXi pos_vector_new = Eigen::VectorXi::Ones(cur_order_size.size()); + int size_iterator = 1; + int size_iterator_new = 1; + Eigen::VectorXi new_order_size = cur_order_size(new_order); + // Calculate the values of the vectors converting position to co-ordinates + for (int i = 1; i < cur_order_size.size(); i++) { + pos_vector(i) = cur_order_size(i - 1) * size_iterator; + pos_vector_new(i) = new_order_size(i - 1) * size_iterator_new; + size_iterator = pos_vector(i); + size_iterator_new = pos_vector_new(i); + } + + // Calculate the new positions with the changed dimensions + Eigen::VectorXi perm_vector = Eigen::VectorXi(cur_order_size.prod()); + for (int i = 0; i < cur_order_size.prod(); i++) { + Eigen::VectorXi nums = Eigen::VectorXi::Zero(cur_order_size.size()); + int size_iterator2 = i; + for (int j = cur_order_size.size() - 1; j > 0; j--) { + nums(j) = size_iterator2 / pos_vector(j); + size_iterator2 = size_iterator2 % pos_vector(j); + } + nums(0) = size_iterator2; + + perm_vector(i) = nums(new_order).transpose() * pos_vector_new; + } + + // Reorder the elements in the matrix + // NB: Test carefully any changes to this. + SparseMD out(cur_order_size.prod(), cur_order_size.prod()); + // Since we are only permuting transition matricies, we have a pretty good + // idea of how populated they are, reserve in advance to improve performance + out.reserve(Eigen::VectorXi::Constant(cur_order_size.prod(), 3)); + + for (int i = 0; i < id_size; i++) { + for (int j = 0; j < matrix.outerSize(); j++) { + for (SparseMD::InnerIterator it(matrix, j); it; ++it) { + out.insert(perm_vector(i * matrix.rows() + it.row()), + perm_vector(i * matrix.cols() + it.col())) = it.value(); + } + } + } + return out; +} + /* * Given a block vector corresponding to an ensemble density, calculate the * marginal for the given index diff --git a/tests/dynamic_COVID_model_test.cc b/tests/dynamic_COVID_model_test.cc index 96b63bc..199d862 100644 --- a/tests/dynamic_COVID_model_test.cc +++ b/tests/dynamic_COVID_model_test.cc @@ -29,13 +29,6 @@ TEST(dynamic_COVID_model_test, system) { std::vector GCM; std::vector countries = read_country_data(num_countries); - for (int i = 0; i < num_countries; i++) { - std::cout << countries.at(i).name << '\n'; - utility::read_matrix( - "../src/data/" + countries.at(i).name + - "_conditional_parameter_expectations.csv"); - } - for (int i = 0; i < num_countries; i++) { country_data country = countries.at(i); Eigen::MatrixXd response_vars = diff --git a/tests/utility_test.cc b/tests/utility_test.cc index b0c5c8e..8c56d4c 100644 --- a/tests/utility_test.cc +++ b/tests/utility_test.cc @@ -166,6 +166,33 @@ TEST(utility_test, permute_matrix) { EXPECT_EQ(new_joint_density, res); } +TEST(utility_test, calc_permuted_kron_identity_product) { + Eigen::VectorXd vec0(2); + vec0 << 1, 2; + Eigen::VectorXd vec1(2); + vec1 << 3, 4; + Eigen::VectorXd vec2(3); + vec2 << 5, 6, 7; + Eigen::MatrixXd mat0 = kroneckerProduct(vec0, vec0.transpose()); + Eigen::MatrixXd mat1 = kroneckerProduct(vec1, vec1.transpose()); + Eigen::MatrixXd mat2 = kroneckerProduct(vec2, vec2.transpose()); + + Eigen::VectorXi new_order(5); + new_order << 0, 2, 1, 3, 4; + Eigen::VectorXi sizes(5); + sizes << 3, 2, 2, 5, 4; + Eigen::MatrixXd joint_density = + kroneckerProduct(mat2, kroneckerProduct(mat1, mat0)).eval(); + Eigen::MatrixXd new_joint_density = + kroneckerProduct(Eigen::MatrixXd::Identity(20, 20), joint_density); + + Eigen::MatrixXd out1 = utility::permute_kron_matrix( + new_joint_density.sparseView(), new_order, sizes); + Eigen::MatrixXd out2 = utility::calc_permuted_kron_identity_product( + 20, joint_density.sparseView(), new_order, sizes); + EXPECT_EQ(out1, out2); +} + TEST(utility_test, find_kron_position) { Eigen::VectorXd vec0(4); vec0 << 1, 2, 3, 4;