From 3a1aaddd8c193f51a4d94bff5c329b779c16e5f5 Mon Sep 17 00:00:00 2001 From: Vissarion Fisikopoulos Date: Sat, 16 Jul 2022 10:19:19 +0100 Subject: [PATCH 01/20] Move compute_diameter functions in one place. --- include/random_walks/compute_diameter.hpp | 203 ++++++++++++++++++ .../gaussian_accelerated_billiard_walk.hpp | 23 +- .../random_walks/uniform_billiard_walk.hpp | 166 +------------- 3 files changed, 205 insertions(+), 187 deletions(-) create mode 100644 include/random_walks/compute_diameter.hpp diff --git a/include/random_walks/compute_diameter.hpp b/include/random_walks/compute_diameter.hpp new file mode 100644 index 000000000..f1d8340b6 --- /dev/null +++ b/include/random_walks/compute_diameter.hpp @@ -0,0 +1,203 @@ +// VolEsti (volume computation and sampling library) + +// Copyright (c) 2012-2022 Vissarion Fisikopoulos +// Copyright (c) 2018-2022 Apostolos Chalkis + +// Licensed under GNU LGPL.3, see LICENCE file + +#ifndef RANDOM_WALKS_COMPUTE_DIAMETER_HPP +#define RANDOM_WALKS_COMPUTE_DIAMETER_HPP + +#include "convex_bodies/ball.h" +#include "convex_bodies/ballintersectconvex.h" +#include "convex_bodies/hpolytope.h" +#include "convex_bodies/spectrahedra/spectrahedron.h" +#ifndef DISABLE_LPSOLVE + #include "convex_bodies/vpolytope.h" + #include "convex_bodies/vpolyintersectvpoly.h" + #include "convex_bodies/zpolytope.h" + #include "convex_bodies/zonoIntersecthpoly.h" +#endif +#include "convex_bodies/orderpolytope.h" +#include "convex_bodies/ellipsoid.h" + + +template +struct compute_diameter +{ + template + static NT compute(GenericPolytope) {return NT(0);} +}; + + +template +struct compute_diameter> +{ + template + static NT compute(HPolytope &P) + { + return NT(2) * std::sqrt(NT(P.dimension())) * P.InnerBall().second; + } +}; + +template +struct compute_diameter> +{ + template + static NT compute(Spectrahedron &P) + { + std::pair inner_ball = P.ComputeInnerBall(); + return NT(6) * NT(P.dimension()) * inner_ball.second; + } +}; + +#ifndef DISABLE_LPSOLVE +template +struct compute_diameter> +{ + template + static NT compute(VPolytope &P) + { + typedef typename VPolytope::MT MT; + NT diameter = NT(0), diam_iter; + MT V = P.get_mat(); + for (int i = 0; i < V.rows(); ++i) { + for (int j = 0; j < V.rows(); ++j) { + if (i != j) { + diam_iter = (V.row(i) - V.row(j)).norm(); + if (diam_iter > diameter) diameter = diam_iter; + } + } + } + return diameter; + } +}; + +template +struct compute_diameter> +{ + template + static NT compute(Zonotope &P) + { + typedef typename Zonotope::MT MT; + typedef typename Zonotope::VT VT; + + MT V = P.get_mat(); + int k = V.rows(), max_index = -1; + MT D = V.transpose() * V; + D = (D + D.transpose()) / 2.0; + Eigen::SelfAdjointEigenSolver es(D); + MT D2 = es.eigenvalues().asDiagonal(), Q = es.eigenvectors(); + + NT max_eig = NT(0); + for (int i = 0; i < P.dimension(); ++i) { + if (es.eigenvalues()[i] > max_eig) { + max_eig = es.eigenvalues()[i]; + max_index = i; + } + } + + VT max_eigvec = -1.0 * Q.col(max_index); + VT obj_fun = max_eigvec.transpose() * V.transpose(), x0(k); + + for (int j = 0; j < k; ++j) x0(j) = (obj_fun(j) < 0.0) ? -1.0 : 1.0; + + return NT(2) * (V.transpose() * x0).norm(); + } +}; + +template +struct compute_diameter, RandomNumberGenerator>> +{ + template + static NT compute(IntersectionOfVpoly, RandomNumberGenerator> &P) + { + return NT(2) * NT(P.dimension()) * P.InnerBall().second; + } +}; + +template +struct compute_diameter, HPolytope>> +{ + template + static NT compute(ZonoIntersectHPoly, HPolytope> &P) + { + typedef typename ZonoIntersectHPoly, HPolytope>::VT VT; + typedef typename ZonoIntersectHPoly, HPolytope>::MT MT; + typedef HPolytope Hpolytope; + + typedef BoostRandomNumberGenerator RandomNumberGenerator; + PushBackWalkPolicy push_back_policy; + typedef typename BCDHRWalk::template Walk + < + Hpolytope, + RandomNumberGenerator + > BCdhrWalk; + typedef BoundaryRandomPointGenerator BCdhrRandomPointGenerator; + + MT G = P.get_T().transpose(); + MT AG = P.get_mat()*G; + int k = G.cols(), d = P.dimension(); + MT eyes1(k, 2*k); + eyes1 << MT::Identity(k,k), NT(-1) * MT::Identity(k,k); + MT M1(k, 4*k); + M1 << AG.transpose(), eyes1; + MT M = M1.transpose(); + VT b = P.get_vec(); + + VT bb(4*k); + for (int i = 0; i < 4*k; ++i) bb(i) = (i < 2*k) ? b(i) : 1.0; + + Hpolytope HP(d, M, bb); + + RandomNumberGenerator rng(HP.dimension()); + + std::list randPoints; + std::pair InnerBall = HP.ComputeInnerBall(); + Point q = InnerBall.first; + BCdhrRandomPointGenerator::apply(HP, q, 4*d*d, 1, + randPoints, push_back_policy, rng); + typename std::list::iterator rpit=randPoints.begin(); + NT max_norm = NT(0), iter_norm; + for ( ; rpit!=randPoints.end(); rpit++) { + iter_norm = (G*(*rpit).getCoefficients()).norm(); + if (iter_norm > max_norm) max_norm = iter_norm; + } + return NT(2) * max_norm; + } +}; + +#endif + +template +struct compute_diameter>> +{ + template + static NT compute(BallIntersectPolytope> &P) + { + return NT(2) * P.radius(); + } +}; + +template +struct compute_diameter> +{ + template + static NT compute(OrderPolytope const& P) + { + return std::sqrt(NT(P.dimension())); + } +}; + +template +struct compute_diameter, Ellipsoid > > +{ + template + static NT compute(BallIntersectPolytope, Ellipsoid> const& P) + { + NT polytope_diameter = std::sqrt(NT(P.dimension())); + return std::min(polytope_diameter, (NT(2) * P.radius())); + } +}; + +#endif // RANDOM_WALKS_COMPUTE_DIAMETER_HPP diff --git a/include/random_walks/gaussian_accelerated_billiard_walk.hpp b/include/random_walks/gaussian_accelerated_billiard_walk.hpp index 5bc87624e..a44608fb2 100644 --- a/include/random_walks/gaussian_accelerated_billiard_walk.hpp +++ b/include/random_walks/gaussian_accelerated_billiard_walk.hpp @@ -18,28 +18,7 @@ #include "sampling/ellipsoid.hpp" #include "random_walks/uniform_billiard_walk.hpp" -template -struct compute_diameter> -{ -template -static NT compute(OrderPolytope const& P) -{ - NT diameter = std::sqrt(NT(P.dimension())); - return diameter; -} -}; - -template -struct compute_diameter, Ellipsoid > > -{ -template -static NT compute(BallIntersectPolytope, Ellipsoid> const& P) -{ - NT polytope_diameter = std::sqrt(NT(P.dimension())); - return std::min(polytope_diameter, (NT(2) * P.radius())); -} -}; - +#include "random_walks/compute_diameter.hpp" // Billiard walk which accelarates each step for uniform distribution and also takes into account // the shape of the polytope for generating directions. diff --git a/include/random_walks/uniform_billiard_walk.hpp b/include/random_walks/uniform_billiard_walk.hpp index 69391c092..90c6378df 100644 --- a/include/random_walks/uniform_billiard_walk.hpp +++ b/include/random_walks/uniform_billiard_walk.hpp @@ -27,171 +27,7 @@ #include "generators/boost_random_number_generator.hpp" #include "sampling/random_point_generators.hpp" #include "volume/sampling_policies.hpp" - -template -struct compute_diameter -{ - template - static NT compute(GenericPolytope) {return NT(0);} -}; - - -template -struct compute_diameter> -{ -template -static NT compute(HPolytope &P) -{ - NT diameter = NT(2) * std::sqrt(NT(P.dimension())) * P.InnerBall().second; - return diameter; -} -}; - -template -struct compute_diameter> -{ -template -static NT compute(Spectrahedron &P) -{ - std::pair inner_ball = P.ComputeInnerBall(); - NT diameter = NT(6) * NT(P.dimension()) * inner_ball.second; - return diameter; -} -}; - -#ifndef DISABLE_LPSOLVE -template -struct compute_diameter> -{ -template -static NT compute(VPolytope &P) -{ - typedef typename VPolytope::MT MT; - NT diameter = NT(0), diam_iter; - MT V = P.get_mat(); - for (int i = 0; i < V.rows(); ++i) { - for (int j = 0; j < V.rows(); ++j) { - if (i != j) { - diam_iter = (V.row(i) - V.row(j)).norm(); - if (diam_iter > diameter) diameter = diam_iter; - } - } - } - return diameter; -} -}; - -template -struct compute_diameter> -{ -template -static NT compute(Zonotope &P) -{ - typedef typename Zonotope::MT MT; - typedef typename Zonotope::VT VT; - - MT V = P.get_mat(); - int k = V.rows(), max_index = -1; - MT D = V.transpose() * V; - D = (D + D.transpose()) / 2.0; - Eigen::SelfAdjointEigenSolver es(D); - MT D2 = es.eigenvalues().asDiagonal(), Q = es.eigenvectors(); - - NT max_eig = NT(0); - for (int i = 0; i < P.dimension(); ++i) { - if (es.eigenvalues()[i] > max_eig) { - max_eig = es.eigenvalues()[i]; - max_index = i; - } - } - - VT max_eigvec = -1.0 * Q.col(max_index); - VT obj_fun = max_eigvec.transpose() * V.transpose(), x0(k); - - for (int j = 0; j < k; ++j) x0(j) = (obj_fun(j) < 0.0) ? -1.0 : 1.0; - - NT diameter = NT(2) * (V.transpose() * x0).norm(); - return diameter; -} -}; - -template -struct compute_diameter, RandomNumberGenerator>> -{ -template -static NT compute(IntersectionOfVpoly, RandomNumberGenerator> &P) -{ - NT diameter = NT(2) * NT(P.dimension()) * P.InnerBall().second; - return diameter; -} -}; - -template -struct compute_diameter, HPolytope>> -{ -template -static NT compute(ZonoIntersectHPoly, HPolytope> &P) -{ - typedef typename ZonoIntersectHPoly, HPolytope>::VT VT; - typedef typename ZonoIntersectHPoly, HPolytope>::MT MT; - typedef HPolytope Hpolytope; - - typedef BoostRandomNumberGenerator RandomNumberGenerator; - PushBackWalkPolicy push_back_policy; - typedef typename BCDHRWalk::template Walk - < - Hpolytope, - RandomNumberGenerator - > BCdhrWalk; - typedef BoundaryRandomPointGenerator BCdhrRandomPointGenerator; - - MT G = P.get_T().transpose(); - MT AG = P.get_mat()*G; - int k = G.cols(), d = P.dimension(); - MT eyes1(k, 2*k); - eyes1 << MT::Identity(k,k), NT(-1) * MT::Identity(k,k); - MT M1(k, 4*k); - M1 << AG.transpose(), eyes1; - MT M = M1.transpose(); - VT b = P.get_vec(); - - VT bb(4*k); - for (int i = 0; i < 4*k; ++i) bb(i) = (i < 2*k) ? b(i) : 1.0; - - Hpolytope HP(d, M, bb); - - RandomNumberGenerator rng(HP.dimension()); - - std::list randPoints; - std::pair InnerBall = HP.ComputeInnerBall(); - Point q = InnerBall.first; - BCdhrRandomPointGenerator::apply(HP, q, 4*d*d, 1, - randPoints, push_back_policy, rng); - typename std::list::iterator rpit=randPoints.begin(); - NT max_norm = NT(0), iter_norm; - for ( ; rpit!=randPoints.end(); rpit++) { - iter_norm = (G*(*rpit).getCoefficients()).norm(); - if (iter_norm > max_norm) max_norm = iter_norm; - } - NT diameter = NT(2) * max_norm; - return diameter; -} -}; - -#endif - -template -struct compute_diameter>> -{ -template -static NT compute(BallIntersectPolytope> &P) -{ - NT diameter = NT(2) * P.radius(); - return diameter; -} -}; - - +#include "random_walks/compute_diameter.hpp" // Billiard walk for uniform distribution From b2e1d7632a78b96371f97da62efd46dad2aa9b53 Mon Sep 17 00:00:00 2001 From: Vissarion Fisikopoulos Date: Sat, 16 Jul 2022 19:19:00 +0100 Subject: [PATCH 02/20] Fix github actions R-CMD-check-ubuntu issue with devtools. --- .github/workflows/R-CMD-check-ubuntu.yml | 6 +++--- cran_gen/genCRANpkg.R | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/R-CMD-check-ubuntu.yml b/.github/workflows/R-CMD-check-ubuntu.yml index af8c85852..dc066b396 100644 --- a/.github/workflows/R-CMD-check-ubuntu.yml +++ b/.github/workflows/R-CMD-check-ubuntu.yml @@ -33,16 +33,16 @@ jobs: steps: - uses: actions/checkout@v2 - run: sudo apt-get update || true; - sudo apt install build-essential libcurl4-gnutls-dev libxml2-dev libssl-dev; + sudo apt install build-essential libcurl4-gnutls-dev libxml2-dev libssl-dev libgit2-dev libfontconfig1-dev libharfbuzz-dev libfribidi-dev; - - uses: r-lib/actions/setup-r@master + - uses: r-lib/actions/setup-r@v2 with: r-version: ${{ matrix.config.r }} - uses: r-lib/actions/setup-pandoc@master - name: Install dependencies - run: Rscript -e "install.packages(c('devtools', dependencies=TRUE))" -e "install.packages(c('rcmdcheck', 'devtools', 'Rcpp', 'RcppEigen', 'BH', 'testthat', 'downloader', 'xfun'))"; + run: Rscript -e "install.packages(c('testthat', 'pkgload', 'rcmdcheck', 'devtools', 'Rcpp', 'RcppEigen', 'BH', 'downloader', 'xfun', dependencies=TRUE))"; - name: Check env: diff --git a/cran_gen/genCRANpkg.R b/cran_gen/genCRANpkg.R index 741cb1321..f12905f06 100644 --- a/cran_gen/genCRANpkg.R +++ b/cran_gen/genCRANpkg.R @@ -32,7 +32,7 @@ gsub_file( # add lpsolve header files in external library(downloader) -download("https://cran.r-project.org/src/contrib/lpSolve_5.6.15.tar.gz", dest="lpSolve.tar.gz", mode="wb") +download("https://cran.r-project.org/src/contrib/Archive/lpSolve/lpSolve_5.6.15.tar.gz", dest="lpSolve.tar.gz", mode="wb") untar("lpSolve.tar.gz", exdir = path) unlink("lpSolve.tar.gz") dir.create(paste0(path,"/external/LPsolve_src")) From d838b4388fffebc3c912506d080008c669f1946d Mon Sep 17 00:00:00 2001 From: zhanggiene Date: Tue, 6 Sep 2022 19:05:57 +0800 Subject: [PATCH 03/20] Fix build issues related to some examples. (#237) * update README.md and Cmakefile * fix errors * Cmake fix for test --- examples/logconcave/CMakeLists.txt | 26 +++++++++++++------------- examples/logconcave/README.md | 14 ++++++++++++++ test/CMakeLists.txt | 5 +++-- 3 files changed, 30 insertions(+), 15 deletions(-) diff --git a/examples/logconcave/CMakeLists.txt b/examples/logconcave/CMakeLists.txt index 01576e2cf..0448ce3e3 100644 --- a/examples/logconcave/CMakeLists.txt +++ b/examples/logconcave/CMakeLists.txt @@ -8,13 +8,9 @@ project( VolEsti ) -option(DISABLE_NLP_ORACLES "Disable non-linear oracles (used in collocation)" ON) -option(BUILTIN_EIGEN "Use eigen from ../external" OFF) -option(USE_MKL "Use MKL library to build eigen" ON) - CMAKE_MINIMUM_REQUIRED(VERSION 2.4.5) -set(MKLROOT $ENV{HOME}/intel/mkl) +set(MKLROOT /opt/intel/oneapi/mkl/latest) set(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS true) if(COMMAND cmake_policy) @@ -81,6 +77,7 @@ if (USE_MKL) find_library(BLAS NAME libblas.so PATHS /usr/lib/x86_64-linux-gnu /usr/lib/i386-linux-gnu) include_directories (BEFORE ${MKLROOT}/include) set(PROJECT_LIBS ${BLAS_LIBRARIES}) + set(MKL_LINK "-L${MKLROOT}/lib -Wl,-rpath,${MKLROOT}/lib -lmkl_intel_ilp64 -lmkl_sequential -lmkl_core -lpthread -lm -ldl") add_definitions(-DEIGEN_USE_MKL_ALL) endif(USE_MKL) @@ -124,6 +121,7 @@ else () add_definitions(${CXX_COVERAGE_COMPILE_FLAGS} "-lm") add_definitions(${CXX_COVERAGE_COMPILE_FLAGS} "-ldl") add_definitions(${CXX_COVERAGE_COMPILE_FLAGS} "-DBOOST_NO_AUTO_PTR") + add_definitions(${CMAKE_CXX_FLAGS} "-DMKL_ILP64") #add_definitions(${CXX_COVERAGE_COMPILE_FLAGS} "-lgslcblas") #add_definitions( "-O3 -lgsl -lm -ldl -lgslcblas" ) @@ -138,13 +136,15 @@ else () #add_executable (adaptive_step_size adaptive_step_size.cpp) - TARGET_LINK_LIBRARIES(high_dimensional_hmc_rand_poly ${LP_SOLVE} ${BLAS} "-L${MKLROOT}/lib/intel64 -Wl,--no-as-needed -lmkl_intel_ilp64 -lmkl_gnu_thread -lmkl_core -lgomp -lpthread -lm -ldl") - TARGET_LINK_LIBRARIES(high_dimensional_hmc ${LP_SOLVE} ${BLAS} "-L${MKLROOT}/lib/intel64 -Wl,--no-as-needed -lmkl_intel_ilp64 -lmkl_gnu_thread -lmkl_core -lgomp -lpthread -lm -ldl") - #TARGET_LINK_LIBRARIES(adaptive_step_size ${LP_SOLVE} ${BLAS} "-L${MKLROOT}/lib/intel64 -Wl,--no-as-needed -lmkl_intel_ilp64 -lmkl_gnu_thread -lmkl_core -lgomp -lpthread -lm -ldl") - TARGET_LINK_LIBRARIES(simple_ode ${LP_SOLVE} ${BLAS} "-L${MKLROOT}/lib/intel64 -Wl,--no-as-needed -lmkl_intel_ilp64 -lmkl_gnu_thread -lmkl_core -lgomp -lpthread -lm -ldl") - TARGET_LINK_LIBRARIES(simple_sde ${LP_SOLVE} ${BLAS} "-L${MKLROOT}/lib/intel64 -Wl,--no-as-needed -lmkl_intel_ilp64 -lmkl_gnu_thread -lmkl_core -lgomp -lpthread -lm -ldl") - TARGET_LINK_LIBRARIES(simple_uld ${LP_SOLVE} ${BLAS} "-L${MKLROOT}/lib/intel64 -Wl,--no-as-needed -lmkl_intel_ilp64 -lmkl_gnu_thread -lmkl_core -lgomp -lpthread -lm -ldl") - TARGET_LINK_LIBRARIES(simple_hmc ${LP_SOLVE} ${BLAS} "-L${MKLROOT}/lib/intel64 -Wl,--no-as-needed -lmkl_intel_ilp64 -lmkl_gnu_thread -lmkl_core -lgomp -lpthread -lm -ldl") - + TARGET_LINK_LIBRARIES(high_dimensional_hmc_rand_poly ${LP_SOLVE} ${BLAS} ${MKL_LINK} ) + TARGET_LINK_LIBRARIES(high_dimensional_hmc ${LP_SOLVE} ${BLAS} ${MKL_LINK} ) + #TARGET_LINK_LIBRARIES(adaptive_step_size ${LP_SOLVE} ${BLAS} ${MKL_LINK} ) + TARGET_LINK_LIBRARIES(simple_ode ${LP_SOLVE} ${BLAS} ${MKL_LINK} ) + TARGET_LINK_LIBRARIES(simple_sde ${LP_SOLVE} ${BLAS} ${MKL_LINK} ) + TARGET_LINK_LIBRARIES(simple_uld ${LP_SOLVE} ${BLAS} ${MKL_LINK} ) + TARGET_LINK_LIBRARIES(simple_hmc ${LP_SOLVE} ${BLAS} ${MKL_LINK} ) + TARGET_LINK_LIBRARIES(exponential_exact_hmc ${LP_SOLVE} ${BLAS} ${MKL_LINK} ) + TARGET_LINK_LIBRARIES(gaussian_exact_hmc ${LP_SOLVE} ${BLAS} ${MKL_LINK} ) + endif() diff --git a/examples/logconcave/README.md b/examples/logconcave/README.md index 58f45e9d2..47fffa259 100644 --- a/examples/logconcave/README.md +++ b/examples/logconcave/README.md @@ -1,4 +1,18 @@ # Running the Examples + +You have to install the latest mkl +[MKL](https://www.intel.com/content/www/us/en/developer/tools/oneapi/onemkl-download.html) +For example, it is installed in the directory "/opt/intel/oneapi/mkl/2022.1.0". + +Change the environment variable: +```bash +export LD_LIBRARY_PATH=/opt/intel/oneapi/mkl/latest/lib/intel64 +``` +Change the variable in CMakeLists.txt +``` +set(MKLROOT /opt/intel/oneapi/mkl/latest) +``` + Build the example by running the following commands in this directory. ```bash diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 090cf5c79..c0676f5c2 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -19,13 +19,13 @@ set(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS true) if (APPLE) set(MKLROOT /opt/intel/oneapi/mkl/latest) elseif(UNIX) - set(MKLROOT $ENV{HOME}/intel/mkl) + set(MKLROOT /opt/intel/oneapi/mkl/latest) endif() option(DISABLE_NLP_ORACLES "Disable non-linear oracles (used in collocation)" ON) option(BUILTIN_EIGEN "Use eigen from ../external" OFF) -option(USE_MKL "Use MKL library to build eigen" OFF) +option(USE_MKL "Use MKL library to build eigen" ON) if(DISABLE_NLP_ORACLES) add_definitions(-DDISABLE_NLP_ORACLES) @@ -191,6 +191,7 @@ else () add_definitions(${CXX_COVERAGE_COMPILE_FLAGS} "-lm") add_definitions(${CXX_COVERAGE_COMPILE_FLAGS} "-ldl") add_definitions(${CXX_COVERAGE_COMPILE_FLAGS} "-DBOOST_NO_AUTO_PTR") + add_definitions(${CMAKE_CXX_FLAGS} "-DMKL_ILP64") #add_definitions(${CXX_COVERAGE_COMPILE_FLAGS} "-lgslcblas") #add_definitions( "-O3 -lgsl -lm -ldl -lgslcblas" ) From 38f6b34bae2599fd83455a7600e3acbc32ddd189 Mon Sep 17 00:00:00 2001 From: iakoviid <44919975+iakoviid@users.noreply.github.com> Date: Thu, 8 Sep 2022 12:28:06 +0300 Subject: [PATCH 04/20] Constrained Riemannian Hamiltonian Monte Carlo preparation (#238) --- examples/crhmc_prepare/.gitignore | 3 + examples/crhmc_prepare/CMakeLists.txt | 127 ++++ examples/crhmc_prepare/README.md | 20 + examples/crhmc_prepare/crhmc_prepare.cpp | 67 +++ examples/crhmc_prepare/data/cube10.ine | 26 + external/PackedCSparse/FloatArray.h | 307 ++++++++++ external/PackedCSparse/FloatArrayAVX2.h | 222 +++++++ external/PackedCSparse/PackedChol.h | 308 ++++++++++ external/PackedCSparse/SparseMatrix.h | 230 +++++++ external/PackedCSparse/add.h | 102 ++++ external/PackedCSparse/chol.h | 247 ++++++++ external/PackedCSparse/dd_real.h | 303 ++++++++++ external/PackedCSparse/leverage.h | 65 ++ external/PackedCSparse/leverageJL.h | 148 +++++ external/PackedCSparse/multiply.h | 142 +++++ external/PackedCSparse/outerprod.h | 86 +++ external/PackedCSparse/projinv.h | 90 +++ external/PackedCSparse/transpose.h | 90 +++ external/cmake-files/QD.cmake | 54 ++ include/ode_solvers/oracle_functors.hpp | 22 + include/preprocess/crhmc/analytic_center.h | 178 ++++++ include/preprocess/crhmc/crhmc_input.h | 111 ++++ include/preprocess/crhmc/crhmc_problem.h | 659 +++++++++++++++++++++ include/preprocess/crhmc/crhmc_utils.h | 371 ++++++++++++ include/preprocess/crhmc/lewis_center.h | 193 ++++++ include/preprocess/crhmc/opts.h | 54 ++ include/sos/barriers/TwoSidedBarrier.h | 157 +++++ test/CMakeLists.txt | 26 +- test/benchmarks_crhmc.cpp | 116 ++++ test/crhmc_polytope_preparation_test.cpp | 205 +++++++ test/crhmc_polytope_test_output.txt | 343 +++++++++++ 31 files changed, 5070 insertions(+), 2 deletions(-) create mode 100644 examples/crhmc_prepare/.gitignore create mode 100644 examples/crhmc_prepare/CMakeLists.txt create mode 100644 examples/crhmc_prepare/README.md create mode 100644 examples/crhmc_prepare/crhmc_prepare.cpp create mode 100644 examples/crhmc_prepare/data/cube10.ine create mode 100644 external/PackedCSparse/FloatArray.h create mode 100644 external/PackedCSparse/FloatArrayAVX2.h create mode 100644 external/PackedCSparse/PackedChol.h create mode 100644 external/PackedCSparse/SparseMatrix.h create mode 100644 external/PackedCSparse/add.h create mode 100644 external/PackedCSparse/chol.h create mode 100644 external/PackedCSparse/dd_real.h create mode 100644 external/PackedCSparse/leverage.h create mode 100644 external/PackedCSparse/leverageJL.h create mode 100644 external/PackedCSparse/multiply.h create mode 100644 external/PackedCSparse/outerprod.h create mode 100644 external/PackedCSparse/projinv.h create mode 100644 external/PackedCSparse/transpose.h create mode 100644 external/cmake-files/QD.cmake create mode 100644 include/preprocess/crhmc/analytic_center.h create mode 100644 include/preprocess/crhmc/crhmc_input.h create mode 100644 include/preprocess/crhmc/crhmc_problem.h create mode 100644 include/preprocess/crhmc/crhmc_utils.h create mode 100644 include/preprocess/crhmc/lewis_center.h create mode 100644 include/preprocess/crhmc/opts.h create mode 100644 include/sos/barriers/TwoSidedBarrier.h create mode 100644 test/benchmarks_crhmc.cpp create mode 100644 test/crhmc_polytope_preparation_test.cpp create mode 100644 test/crhmc_polytope_test_output.txt diff --git a/examples/crhmc_prepare/.gitignore b/examples/crhmc_prepare/.gitignore new file mode 100644 index 000000000..adf951b74 --- /dev/null +++ b/examples/crhmc_prepare/.gitignore @@ -0,0 +1,3 @@ +coli_crhmc_polytope.txt +crhmc_prepare +libQD_LIB.a diff --git a/examples/crhmc_prepare/CMakeLists.txt b/examples/crhmc_prepare/CMakeLists.txt new file mode 100644 index 000000000..6bdf831b2 --- /dev/null +++ b/examples/crhmc_prepare/CMakeLists.txt @@ -0,0 +1,127 @@ +# VolEsti (volume computation and sampling library) +# Copyright (c) 2012-2021 Vissarion Fisikopoulos +# Copyright (c) 2018-2021 Apostolos Chalkis +# Contributed and/or modified by Ioannis Iakovidis +# Licensed under GNU LGPL.3, see LICENCE file + +project( VolEsti ) + +CMAKE_MINIMUM_REQUIRED(VERSION 3.11) + +set(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS true) + +# Locate Intel MKL root (in case it is enabled) +if (APPLE) + set(MKLROOT /opt/intel/oneapi/mkl/latest) +elseif(UNIX) + #set(MKLROOT /opt/intel/oneapi/mkl/latest) + set(MKLROOT $ENV{HOME}/intel/mkl) +endif() + +if(COMMAND cmake_policy) + cmake_policy(SET CMP0003 NEW) +endif(COMMAND cmake_policy) + + +option(DISABLE_NLP_ORACLES "Disable non-linear oracles (used in collocation)" ON) +option(BUILTIN_EIGEN "Use eigen from ../../external" OFF) +option(USE_MKL "Use MKL library to build eigen" OFF) + + +if(DISABLE_NLP_ORACLES) + add_definitions(-DDISABLE_NLP_ORACLES) +else() + find_library(IFOPT NAMES libifopt_core.so PATHS /usr/local/lib) + find_library(IFOPT_IPOPT NAMES libifopt_ipopt.so PATHS /usr/local/lib) + find_library(GMP NAMES libgmp.so PATHS /usr/lib/x86_64-linux-gnu /usr/lib/i386-linux-gnu) + find_library(MPSOLVE NAMES libmps.so PATHS /usr/local/lib) + find_library(PTHREAD NAMES libpthread.so PATHS /usr/lib/x86_64-linux-gnu /usr/lib/i386-linux-gnu) + find_library(FFTW3 NAMES libfftw3.so.3 PATHS /usr/lib/x86_64-linux-gnu /usr/lib/i386-linux-gnu) + + if (NOT IFOPT) + + message(FATAL_ERROR "This program requires the ifopt library, and will not be compiled.") + + elseif (NOT GMP) + + message(FATAL_ERROR "This program requires the gmp library, and will not be compiled.") + + elseif (NOT MPSOLVE) + + message(FATAL_ERROR "This program requires the mpsolve library, and will not be compiled.") + + elseif (NOT FFTW3) + + message(FATAL_ERROR "This program requires the fftw3 library, and will not be compiled.") + + else() + message(STATUS "Library ifopt found: ${IFOPT}") + message(STATUS "Library gmp found: ${GMP}") + message(STATUS "Library mpsolve found: ${MPSOLVE}") + message(STATUS "Library fftw3 found:" ${FFTW3}) + + endif(NOT IFOPT) + +endif(DISABLE_NLP_ORACLES) + +include("../../external/cmake-files/Eigen.cmake") +GetEigen() + +include("../../external/cmake-files/Boost.cmake") +GetBoost() + +include("../../external/cmake-files/LPSolve.cmake") +GetLPSolve() + +include("../../external/cmake-files/QD.cmake") +GetQD() + +# Find lpsolve library +find_library(LP_SOLVE NAMES liblpsolve55.so PATHS /usr/lib/lp_solve) + +if (NOT LP_SOLVE) + message(FATAL_ERROR "This program requires the lp_solve library, and will not be compiled.") +else () + + message(STATUS "Library lp_solve found: ${LP_SOLVE}") + set(CMAKE_EXPORT_COMPILE_COMMANDS "ON") + + if (USE_MKL) + find_library(BLAS NAMES libblas.so libblas.dylib PATHS /usr/local/Cellar/lapack/3.9.1_1/lib /usr/lib/x86_64-linux-gnu /usr/lib/i386-linux-gnu /usr/local/Cellar/openblas/0.3.15_1/lib /usr/lib) + find_library(GFORTRAN NAME libgfortran.dylib PATHS /usr/local/Cellar/gcc/10.2.0_4/lib/gcc/10) + find_library(LAPACK NAME liblapack.dylib PATHS /usr/lib) + find_library(OPENMP NAME libiomp5.dylib PATHS /opt/intel/oneapi/compiler/2021.1.1/mac/compiler/lib) + + include_directories (BEFORE ${MKLROOT}/include) + set(PROJECT_LIBS ${BLAS_LIBRARIES} ${LAPACK_LIBRARIES} ${GFORTRAN_LIBRARIES}) + set(MKL_LINK "-L${MKLROOT}/lib -Wl,-rpath,${MKLROOT}/lib -lmkl_intel_ilp64 -lmkl_sequential -lmkl_core -lpthread -lm -ldl") + add_definitions(-DEIGEN_USE_MKL_ALL) + else() + set(MKL_LINK "") + endif(USE_MKL) + + include_directories (BEFORE ../../external) + include_directories (BEFORE ../../external/minimum_ellipsoid) + include_directories (BEFORE ../../include/) + + # for Eigen + if (${CMAKE_VERSION} VERSION_LESS "3.12.0") + add_compile_options(-D "EIGEN_NO_DEBUG") + else () + add_compile_definitions("EIGEN_NO_DEBUG") + endif () + + + add_definitions(${CMAKE_CXX_FLAGS} "-std=c++11") # enable C++11 standard + #add_definitions(${CMAKE_CXX_FLAGS} "-g") # enable debuger + set(ADDITIONAL_FLAGS "-march=native -DSIMD_LEN=0 -DTIME_KEEPING") + add_definitions(${CMAKE_CXX_FLAGS} "-O3 " ${ADDITIONAL_FLAGS}) # optimization of the compiler + #add_definitions(${CXX_COVERAGE_COMPILE_FLAGS} "-lgsl") + add_definitions(${CXX_COVERAGE_COMPILE_FLAGS} "-lm") + add_definitions(${CXX_COVERAGE_COMPILE_FLAGS} "-ldl") + add_definitions(${CXX_COVERAGE_COMPILE_FLAGS} "-DBOOST_NO_AUTO_PTR") + + add_executable (crhmc_prepare crhmc_prepare.cpp) + TARGET_LINK_LIBRARIES(crhmc_prepare ${QD_LIB} ${MKL_LINK} ${LP_SOLVE}) + +endif() diff --git a/examples/crhmc_prepare/README.md b/examples/crhmc_prepare/README.md new file mode 100644 index 000000000..715526981 --- /dev/null +++ b/examples/crhmc_prepare/README.md @@ -0,0 +1,20 @@ +## Constrained Riemannian Hamiltonian Monte Carlo for Polytopes +This is an example that illustrates the simplification and preparation process. + +References: +Yunbum Kook, Yin Tat Lee, Ruoqi Shen, Santosh S. Vempala. "Sampling with Riemannian Hamiltonian + Monte Carlo in a Constrained Space" +## Compilation +Build the example by running the following commands in this directory. + +```bash +cmake . -DLP_SOLVE=_PATH_TO_LIB_FILE +make +``` +You have to specify the path to liblpsolve55.so/dll/dylib. +For example: -DLP_SOLVE=/usr/lib/lpsolve/liblpsolve55.so + +## Running: +```bash + ./crhmc_prepare [filepath] +``` diff --git a/examples/crhmc_prepare/crhmc_prepare.cpp b/examples/crhmc_prepare/crhmc_prepare.cpp new file mode 100644 index 000000000..540900324 --- /dev/null +++ b/examples/crhmc_prepare/crhmc_prepare.cpp @@ -0,0 +1,67 @@ +// VolEsti (volume computation and sampling library) + +// Copyright (c) 2012-2020 Vissarion Fisikopoulos +// Copyright (c) 2018-2020 Apostolos Chalkis +// Copyright (c) 2022-2022 Ioannis Iakovidis + +// Contributed and/or modified by Ioannis Iakovidis, as part of Google Summer of +// Code 2022 program. + +// Licensed under GNU LGPL.3, see LICENCE file + +// References +// Yunbum Kook, Yin Tat Lee, Ruoqi Shen, Santosh S. Vempala. "Sampling with +// Riemannian Hamiltonian +// Monte Carlo in a Constrained Space" +#include "Eigen/Eigen" +#include "cartesian_geom/cartesian_kernel.h" +#include "convex_bodies/hpolytope.h" +#include "generators/known_polytope_generators.h" +#include "misc/misc.h" +#include "preprocess/crhmc/crhmc_input.h" +#include "preprocess/crhmc/crhmc_problem.h" +#include +#include +#include /* clock_t, clock, CLOCKS_PER_SEC */ +#include + +using NT = double; +using Kernel = Cartesian; +using Point = Kernel::Point; +using PolytopeType = HPolytope; +using MT = Eigen::Matrix; +using VT = Eigen::Matrix; +using Input = crhmc_input; +using CrhmcProblem = crhmc_problem; +using Opts = opts; + +int main(int argc, char *argv[]) +{ + if (argc != 2) + { + std::cout << "Usage: ./crhmc_prepare [file_name_string]\n"; + std::cout << "Example file name= " + "../../test/metabolic_full_dim/polytope_e_coli.ine\n"; + exit(1); + } + std::string fileName(argv[1]); + std::cout << "Reading input from file..." << std::endl; + std::ifstream inp; + std::vector> Pin; + inp.open(fileName, std::ifstream::in); + read_pointset(inp, Pin); + + PolytopeType HP(Pin); + int d = HP.dimension(); + Input input = Input(d); + input.Aineq = HP.get_mat(); + input.bineq = HP.get_vec(); + Opts options; + options.EnableReordering = false; + double tstart = (double)clock() / (double)CLOCKS_PER_SEC; + CrhmcProblem P = CrhmcProblem(input, options); + std::cout << "Preparation completed in time, "; + std::cout << (double)clock() / (double)CLOCKS_PER_SEC - tstart << std::endl; + std::cout << "Number of nonZeros= " << P.Asp.nonZeros() << "\n"; + return 0; +} diff --git a/examples/crhmc_prepare/data/cube10.ine b/examples/crhmc_prepare/data/cube10.ine new file mode 100644 index 000000000..a750ed5b4 --- /dev/null +++ b/examples/crhmc_prepare/data/cube10.ine @@ -0,0 +1,26 @@ +cube10.ine +H-representation +begin + 20 11 real + 1 1 0 0 0 0 0 0 0 0 0 + 1 0 1 0 0 0 0 0 0 0 0 + 1 0 0 1 0 0 0 0 0 0 0 + 1 0 0 0 1 0 0 0 0 0 0 + 1 0 0 0 0 1 0 0 0 0 0 + 1 0 0 0 0 0 1 0 0 0 0 + 1 0 0 0 0 0 0 1 0 0 0 + 1 0 0 0 0 0 0 0 1 0 0 + 1 0 0 0 0 0 0 0 0 1 0 + 1 0 0 0 0 0 0 0 0 0 1 + 1 -1 0 0 0 0 0 0 0 0 0 + 1 0 -1 0 0 0 0 0 0 0 0 + 1 0 0 -1 0 0 0 0 0 0 0 + 1 0 0 0 -1 0 0 0 0 0 0 + 1 0 0 0 0 -1 0 0 0 0 0 + 1 0 0 0 0 0 -1 0 0 0 0 + 1 0 0 0 0 0 0 -1 0 0 0 + 1 0 0 0 0 0 0 0 -1 0 0 + 1 0 0 0 0 0 0 0 0 -1 0 + 1 0 0 0 0 0 0 0 0 0 -1 +end +input_incidence diff --git a/external/PackedCSparse/FloatArray.h b/external/PackedCSparse/FloatArray.h new file mode 100644 index 000000000..28d1c5da6 --- /dev/null +++ b/external/PackedCSparse/FloatArray.h @@ -0,0 +1,307 @@ +// VolEsti (volume computation and sampling library) + +// Copyright (c) 2012-2018 Vissarion Fisikopoulos +// Copyright (c) 2018 Apostolos Chalkis +// Copyright (c) 2022 Ioannis Iakovidis + +// This file is converted from PolytopeSamplerMatlab +//(https://github.com/ConstrainedSampler/PolytopeSamplerMatlab/blob/master/code/solver/PackedCSparse/PackedChol.h) by Ioannis Iakovidis + +#pragma once +#include +#include +#include +namespace PackedCSparse { + template + struct BaseImpl + { + T x[k]; + + BaseImpl() {}; + + BaseImpl(const T& rhs) + { + for (size_t i = 0; i < k; i++) + x[i] = rhs; + } + + BaseImpl operator+(const BaseImpl& rhs) const + { + BaseImpl lhs; + for (size_t i = 0; i < k; i++) + lhs.x[i] = x[i] + rhs.x[i]; + return lhs; + } + + BaseImpl operator-(const BaseImpl& rhs) const + { + BaseImpl lhs; + for (size_t i = 0; i < k; i++) + lhs.x[i] = x[i] - rhs.x[i]; + return lhs; + } + + BaseImpl operator*(const BaseImpl& rhs) const + { + BaseImpl lhs; + for (size_t i = 0; i < k; i++) + lhs.x[i] = x[i] * rhs.x[i]; + return lhs; + } + + BaseImpl operator/(const BaseImpl& rhs) const + { + BaseImpl lhs; + for (size_t i = 0; i < k; i++) + lhs.x[i] = x[i] / rhs.x[i]; + return lhs; + } + + BaseImpl& operator+=(const BaseImpl& rhs) + { + for (size_t i = 0; i < k; i++) + x[i] += rhs.x[i]; + return *this; + } + + BaseImpl& operator-=(const BaseImpl& rhs) + { + for (size_t i = 0; i < k; i++) + x[i] -= rhs.x[i]; + return *this; + } + + BaseImpl& operator*=(const BaseImpl& rhs) + { + for (size_t i = 0; i < k; i++) + x[i] *= rhs.x[i]; + return *this; + } + + BaseImpl& operator/=(const BaseImpl& rhs) + { + for (size_t i = 0; i < k; i++) + x[i] /= rhs.x[i]; + return *this; + } + + explicit operator bool() const + { + bool ret = false; + for (size_t i = 0; i < k; i++) + ret = ret || bool(x[i]); + return ret; + } + + static T get(const BaseImpl& a, size_t index) + { + return a.x[index]; + } + + static void set(BaseImpl& a, size_t index, const T& value) + { + a.x[index] = value; + } + + static BaseImpl abs(const BaseImpl& a) + { + BaseImpl out; + for (size_t i = 0; i < k; i++) + out.x[i] = std::abs(a.x[i]); + return out; + } + + static BaseImpl log(const BaseImpl& a) + { + BaseImpl out; + for (size_t i = 0; i < k; i++) + out.x[i] = std::log(a.x[i]); + return out; + } + + static void fmadd(BaseImpl& a, const BaseImpl& b, const BaseImpl& c) + { + for (size_t i = 0; i < k; i++) + a.x[i] += b.x[i] * c.x[i]; + } + + static void fnmadd(BaseImpl& a, const BaseImpl& b, const BaseImpl& c) + { + for (size_t i = 0; i < k; i++) + a.x[i] -= b.x[i] * c.x[i]; + } + + static void fmadd(BaseImpl& a, const BaseImpl& b, const T& c) + { + for (size_t i = 0; i < k; i++) + a.x[i] += b.x[i] * c; + } + + static void fnmadd(BaseImpl& a, const BaseImpl& b, const T& c) + { + for (size_t i = 0; i < k; i++) + a.x[i] -= b.x[i] * c; + } + + static BaseImpl clipped_sqrt(const BaseImpl& a, const T nonpos_output) + { + BaseImpl out; + for (size_t i = 0; i < k; i++) + { + T r = a.x[i]; + if (r > 0) + out.x[i] = sqrt(r); + else + out.x[i] = nonpos_output; + } + return out; + } + + static BaseImpl sign(std::mt19937_64& gen) + { + BaseImpl out; + unsigned long long seed = gen(); + for (size_t i = 0; i < k; i++) + { + out.x[i] = T((2 * ((seed >> i) & 1)) - 1.0); + if ((i & 63) == 63) seed = gen(); + } + return out; + } + + }; + + template + struct BaseScalarImpl + { + static T get(const T& x, size_t index) + { + return x; + } + + static void set(T& x, size_t index, T& value) + { + x = value; + } + + static T abs(const T &x) + { + return ::abs(x); + } + + static T log(const T &x) + { + return ::log(x); + } + + static void fmadd(T& a, const T& b, const T& c) + { + a += b * c; + } + + static void fnmadd(T& a, const T& b, const T& c) + { + a -= b * c; + } + + static T clipped_sqrt(const T& x, const T& nonpos_output) + { + if (x > 0.0) + return sqrt(x); + else + return nonpos_output; + } + + static T sign(std::mt19937_64& gen) + { + unsigned long long seed = gen(); + return T((2 * (seed & 1)) - 1.0); + } + }; + + template + struct FloatTypeSelector + { + using type = typename std::conditional>::type; + using funcImpl = typename std::conditional, BaseImpl>::type; + }; + + #ifdef __AVX2__ + #include "FloatArrayAVX2.h" + #else + template + struct FloatTypeSelector + { + using type = typename std::conditional< k == 1, double, BaseImpl>::type; + using funcImpl = typename std::conditional< k == 1, BaseScalarImpl, BaseImpl>::type; + }; + + template + struct FloatTypeSelector, l> + { + using type = BaseImpl; + using funcImpl = BaseImpl; + }; + #endif + + template + struct FloatTypeSelector, l> + { + using type = BaseImpl; + using funcImpl = BaseImpl; + }; + + template + using FloatArray = typename FloatTypeSelector::type; + + template + using FloatArrayFunc = typename FloatTypeSelector::funcImpl; + + template + auto get(const T& a, size_t index) -> decltype(FloatArrayFunc::get(a, index)) + { + return FloatArrayFunc::get(a, index); + } + + template + void set(T1& a, size_t index, T2 value) + { + FloatArrayFunc::set(a, index, value); + } + + template + void fmadd(T1& a, const T2& b, const T3& c) + { + FloatArrayFunc::fmadd(a, b, c); + } + + template + void fnmadd(T1& a, const T2& b, const T3& c) + { + FloatArrayFunc::fnmadd(a, b, c); + } + + template + T1 clipped_sqrt(const T1& a, const T2 b) + { + return FloatArrayFunc::clipped_sqrt(a, b); + } + + template + T abs(const T& a) + { + return FloatArrayFunc::abs(a); + } + + template + T log(const T& a) + { + return FloatArrayFunc::log(a); + } + + template + T sign(std::mt19937_64& gen) + { + return FloatArrayFunc::sign(gen); + } +} diff --git a/external/PackedCSparse/FloatArrayAVX2.h b/external/PackedCSparse/FloatArrayAVX2.h new file mode 100644 index 000000000..3ae7592a7 --- /dev/null +++ b/external/PackedCSparse/FloatArrayAVX2.h @@ -0,0 +1,222 @@ +// VolEsti (volume computation and sampling library) + +// Copyright (c) 2012-2018 Vissarion Fisikopoulos +// Copyright (c) 2018 Apostolos Chalkis +// Copyright (c) 2022 Ioannis Iakovidis + +// This file is converted from PolytopeSamplerMatlab +//(https://github.com/ConstrainedSampler/PolytopeSamplerMatlab/blob/master/code/solver/PackedCSparse/PackedChol.h) by Ioannis Iakovidis + +template + struct m256dArray +{ + __m256d x[k]; + + m256dArray() {}; + + m256dArray(const double rhs) + { + for (size_t i = 0; i < k; i++) + x[i] = _mm256_set1_pd(rhs); + } + + template + m256dArray(const m256dArray& rhs) + { + for (size_t i = 0; i < k; i++) + x[i] = rhs.x[i % k2]; + } + + m256dArray operator+(const m256dArray& rhs) const + { + m256dArray out; + for (size_t i = 0; i < k; i++) + out.x[i] = _mm256_add_pd(x[i], rhs.x[i]); + return out; + } + + m256dArray operator-(const m256dArray& rhs) const + { + m256dArray out; + for (size_t i = 0; i < k; i++) + out.x[i] = _mm256_sub_pd(x[i], rhs.x[i]); + return out; + } + + m256dArray operator*(const m256dArray& rhs) const + { + m256dArray out; + for (size_t i = 0; i < k; i++) + out.x[i] = _mm256_mul_pd(x[i], rhs.x[i]); + return out; + } + + m256dArray operator/(const m256dArray& rhs) const + { + m256dArray out; + for (size_t i = 0; i < k; i++) + out.x[i] = _mm256_div_pd(x[i], rhs.x[i]); + return out; + } + + m256dArray& operator+=(const m256dArray& rhs) + { + for (size_t i = 0; i < k; i++) + x[i] = _mm256_add_pd(x[i], rhs.x[i]); + return *this; + } + + m256dArray& operator-=(const m256dArray& rhs) + { + for (size_t i = 0; i < k; i++) + x[i] = _mm256_sub_pd(x[i], rhs.x[i]); + return *this; + } + + m256dArray& operator*=(const m256dArray& rhs) + { + for (size_t i = 0; i < k; i++) + x[i] = _mm256_mul_pd(x[i], rhs.x[i]); + return *this; + } + + m256dArray& operator/=(const m256dArray& rhs) + { + for (size_t i = 0; i < k; i++) + x[i] = _mm256_div_pd(x[i], rhs.x[i]); + return *this; + } + + explicit operator bool() const + { + bool ret = false; + __m256d z = _mm256_set1_pd(0.0); + for (size_t i = 0; i < k; i++) + { + __m256d c = _mm256_cmp_pd(x[i], z, _CMP_EQ_OQ); + ret = ret || (_mm256_movemask_pd(c) != 0xf); + } + return ret; + } + + static double get(const m256dArray& x, size_t index) + { + double y[4]; + _mm256_store_pd(y, x.x[index / 4]); + return y[index & 3]; + } + + static void set(m256dArray& x, size_t index, double value) + { + __m256d v = _mm256_broadcast_sd(&value); + switch (index & 3) + { + case 0: x.x[index / 4] = _mm256_blend_pd(x.x[index / 4], v, 1); break; + case 1: x.x[index / 4] = _mm256_blend_pd(x.x[index / 4], v, 2); break; + case 2: x.x[index / 4] = _mm256_blend_pd(x.x[index / 4], v, 4); break; + default: x.x[index / 4] = _mm256_blend_pd(x.x[index / 4], v, 8); break; + } + } + + static m256dArray abs(const m256dArray& x) + { + const __m256d mask = _mm256_castsi256_pd(_mm256_set1_epi64x(0x7FFFFFFFFFFFFFFF)); + + m256dArray out; + for (size_t i = 0; i < k; i++) + out.x[i] = _mm256_and_pd(x.x[i], mask); + return out; + } + + static m256dArray log(const m256dArray& x) + { + // gcc does not support _mm256_log_pd + // Do it sequentially instead + + //m256dArray out; + //for (size_t i = 0; i < k; i++) + // out.x[i] = _mm256_log_pd(x.x[i]); + + m256dArray out; + for (size_t i = 0; i < 4*k; i++) + set(out, i, std::log(get(x,i))); + return out; + } + + static void fmadd(m256dArray& a, const m256dArray& b, const double& c) + { + auto cx = _mm256_set1_pd(c); + for (size_t i = 0; i < k; i++) + a.x[i] = _mm256_fmadd_pd(b.x[i], cx, a.x[i]); + } + + static void fnmadd(m256dArray& a, const m256dArray& b, const double& c) + { + auto cx = _mm256_set1_pd(c); + for (size_t i = 0; i < k; i++) + a.x[i] = _mm256_fnmadd_pd(b.x[i], cx, a.x[i]); + } + + static void fmadd(m256dArray& a, const m256dArray& b, const m256dArray& c) + { + for (size_t i = 0; i < k; i++) + a.x[i] = _mm256_fmadd_pd(b.x[i], c.x[i], a.x[i]); + } + + static void fnmadd(m256dArray& a, const m256dArray& b, const m256dArray& c) + { + for (size_t i = 0; i < k; i++) + a.x[i] = _mm256_fnmadd_pd(b.x[i], c.x[i], a.x[i]); + } + + static m256dArray clipped_sqrt(const m256dArray& x, const double nonpos_output) + { + m256dArray out; + + const __m256d large = { nonpos_output, nonpos_output, nonpos_output, nonpos_output }; + const __m256d zero = _mm256_setzero_pd(); + for (size_t i = 0; i < k; i++) + { + __m256d xi = x.x[i]; + __m256d mask = _mm256_cmp_pd(xi, zero, _CMP_LE_OS); // mask = (rhs.x[i]<= 0) ? -1 : 0 + out.x[i] = _mm256_blendv_pd(_mm256_sqrt_pd(xi), large, mask); + } + return out; + } + + static m256dArray sign(std::mt19937_64& gen) + { + m256dArray out; + const __m256i bits = _mm256_set_epi64x(1, 2, 4, 8); + const __m256d zero = _mm256_setzero_pd(); + const __m256d pos = _mm256_set_pd(1.0, 1.0, 1.0, 1.0); + const __m256d neg = _mm256_set_pd(-1.0, -1.0, -1.0, -1.0); + + unsigned long long seed = gen(); + for (size_t i = 0; i < k; i++) + { + __m256i s = _mm256_set1_epi64x((seed >> (4 * i)) & 15); + __m256i xi = _mm256_and_si256(s, bits); + __m256d x = _mm256_castsi256_pd(xi); + __m256d mask = _mm256_cmp_pd(x, zero, _CMP_EQ_OQ); // mask = (rhs.x[i] == 0) ? -1 : 0 + out.x[i] = _mm256_blendv_pd(pos, neg, mask); + if ((i & 63) == 63) seed = gen(); + } + return out; + } +}; + +template + struct FloatTypeSelector +{ + static_assert(k == 1 || k % 4 == 0, "Array assumes k = 1 or a multiple of 4"); + using type = typename std::conditional< k == 1, double, m256dArray>::type; + using funcImpl = typename std::conditional< k == 1, BaseScalarImpl, m256dArray>::type; +}; + +template + struct FloatTypeSelector, l> +{ + using type = m256dArray; + using funcImpl = m256dArray; +}; diff --git a/external/PackedCSparse/PackedChol.h b/external/PackedCSparse/PackedChol.h new file mode 100644 index 000000000..57a2b9232 --- /dev/null +++ b/external/PackedCSparse/PackedChol.h @@ -0,0 +1,308 @@ +// VolEsti (volume computation and sampling library) + +// Copyright (c) 2012-2018 Vissarion Fisikopoulos +// Copyright (c) 2018 Apostolos Chalkis +// Copyright (c) 2022 Ioannis Iakovidis + +// This file is converted from PolytopeSamplerMatlab +//(https://github.com/ConstrainedSampler/PolytopeSamplerMatlab/blob/master/code/solver/PackedCSparse/PackedChol.h) by Ioannis Iakovidis + +#pragma once +#include "Eigen/Eigen" +#include "SparseMatrix.h" +#include "chol.h" +#include "leverage.h" +#include "leverageJL.h" +#include "multiply.h" +#include "dd_real.h" +#include +#include +using namespace PackedCSparse; + +template +void get_slice(Tout *out, Tin *in, size_t n, size_t idx) { + for (size_t j = 0; j < n; j++) + out[j] = to_double(get(in[j], idx)); +} + +template +void set_slice(Tout *out, Tin *in, size_t n, size_t idx) { + for (size_t j = 0; j < n; j++) + set(out[j], idx, to_double(in[j])); +} + +template struct PackedChol { + using Tx = double; + using Tx2 = FloatArray; + using Te = dd_real; + + // parameters + SparseMatrix A; + SparseMatrix At; + UniqueAlignedPtr w; + Tx accuracyThreshold = 1e-6; + std::vector + exactIdx; // k size array. Indices we perform high precision calculation + std::vector + numExact; // number of times we perform high precision decompose (length + // k+1, the last one records how many times we do decompose) + bool decomposed = false; + + // preprocess info for different CSparse operations (PackedDouble) + MultiplyOutput H; // cache for H = A W A' + CholOutput L; // cache for L = chol(H) + LeverageOutput diagP; // cache for L = chol(H) + LeverageJLOutput diagPJL; // cache for L = chol(H) + + // preprocess info for different CSparse operations (dd_real) + MultiplyOutput H_exact; // cache for H = A W A' + CholOutput L_exact; // cache for L = chol(H) + LeverageOutput diagP_exact; // cache for L = chol(H) + LeverageJLOutput diagPJL_exact; // cache for L = chol(H) + SparseMatrix Le[k]; // store output of L_exact + + PackedChol(const SparseMatrix &A_) { + A = std::move(A_.clone()); + At = transpose(A); + w.reset(pcs_aligned_new(A.n)); + numExact.resize(k + 1); + } + + void setSeed(unsigned long long seed) { + diagPJL.gen.seed(seed); + diagPJL_exact.gen.seed(seed); + } + + bool allExact() { return exactIdx.size() == k; } + + bool hasExact() { return exactIdx.size() > 0; } + + template Tx2 decompose(const Tv2_ *w_in) { + + Tx2 acc = Tx2(0.0); + + // record w + Ti n = A.n; + + for (Ti j = 0; j < n; j++) { + w[j] = w_in[j]; + } + // compute chol + ++numExact[k]; + if (accuracyThreshold > 0.0 || + !decomposed) // the first time we call, always run the double chol. + { + multiply(H, A, w.get(), At); + chol(L, H); + decomposed = true; + + exactIdx.clear(); + acc = estimateAccuracy(); + for (size_t i = 0; i < k; i++) { + if (get(acc, i) >= + accuracyThreshold) // >= is important for the case accuracyThreshold + // = 0.0, we need to compute everything exactly + exactIdx.push_back(i); + } + } else if (!allExact()) { + exactIdx.clear(); + for (size_t i = 0; i < k; i++) + exactIdx.push_back(i); + } + + if (hasExact()) { + Te *w_exact = new Te[n]; + + for (size_t i : exactIdx) { + ++numExact[i]; + get_slice(w_exact, w.get(), n, i); + multiply(H_exact, A, w_exact, At); + chol(L_exact, H_exact); + + // copy result to Le[i] + if (!Le[i].initialized()) + Le[i] = std::move(L_exact.template clone()); + else { + Ti nz = L_exact.nnz(); + for (Ti s = 0; s < nz; ++s) + Le[i].x[s] = (L_exact.x[s]); + } + } + + delete[] w_exact; + } + return acc; + } + + Tx2 logdet() { + pcs_assert(decomposed, "logdet: Need to call decompose first."); + + Ti m = A.m; + Tx2 ret = Tx2(0); + + if (!allExact()) { + Ti *Lp = L.p.get(); + Tx2 *Lx = L.x.get(); + for (Ti j = 0; j < m; j++) + ret += log(Lx[Lp[j]]); + } + + if (hasExact()) { + for (size_t i : exactIdx) { + Te ret_e = 0.0; + Ti *Lp = Le[i].p.get(); + Te *Lx = Le[i].x.get(); + + for (Ti j = 0; j < m; j++) + ret_e += log(Lx[Lp[j]]); + + set(ret, i, to_double(ret_e)); + } + } + + return ret * Tx2(2.0); + } + + void diagL(Tx2 *out) { + pcs_assert(decomposed, "diagL: Need to call decompose first."); + + Ti m = A.m; + + if (!allExact()) { + Ti *Li = L.i.get(), *Lp = L.p.get(); + Tx2 *Lx = L.x.get(); + for (Ti j = 0; j < m; j++) + out[j] = Lx[Lp[j]]; + } + + if (hasExact()) { + for (size_t i : exactIdx) { + Ti *Lp = Le[i].p.get(); + Te *Lx = Le[i].x.get(); + + for (Ti j = 0; j < m; j++) + set(out[j], i, to_double(Lx[Lp[j]])); + } + } + } + + SparseMatrix getL(Ti i) { + pcs_assert(decomposed, "getL: Need to call decompose first."); + + Ti m = L.m, n = L.n, nz = L.nnz(); + SparseMatrix out(m, n, nz); + + Ti *outp = out.p.get(), *Lp = L.p.get(); + Ti *outi = out.i.get(), *Li = L.i.get(); + + for (Ti s = 0; s <= n; s++) + outp[s] = Lp[s]; + + for (Ti s = 0; s < nz; s++) + outi[s] = Li[s]; + + bool isExact = false; + for (size_t i_ : exactIdx) { + if (i_ == i) + isExact = true; + } + + double *outx = out.x.get(); + if (isExact) { + Te *Lx = Le[i].x.get(); + for (Ti s = 0; s < nz; s++) + outx[s] = to_double(Lx[s]); + } else { + Tx2 *Lx = L.x.get(); + for (Ti s = 0; s < nz; s++) + outx[s] = get(Lx[s], i); + } + + return std::move(out); + } + + void solve(Tx2 *b, Tx2 *out) { + pcs_assert(decomposed, "solve: Need to call decompose first."); + + if (!allExact()) { + lsolve(L, b, out); + ltsolve(L, out, out); + } + + if (hasExact()) { + Ti m = A.m; + Te *b_exact = new Te[m]; + Te *out_exact = new Te[m]; + + for (size_t i : exactIdx) { + get_slice(b_exact, b, m, i); + lsolve(Le[i], b_exact, out_exact); + ltsolve(Le[i], out_exact, out_exact); + set_slice(out, out_exact, m, i); + } + + delete[] b_exact; + delete[] out_exact; + } + }; + + void leverageScoreComplement(Tx2 *out) { + pcs_assert(decomposed, + "leverageScoreComplement: Need to call decompose first."); + + Ti n = A.n, m = A.m; + + if (!allExact()) { + Tx2 T1 = Tx2(1.0), T2 = Tx2(2.0); + leverage(diagP, L, A, At); + + Tx2 *tau = diagP.x.get(); + for (Ti j = 0; j < n; j++) + out[j] = T1 - tau[j] * w[j]; + } + + if (hasExact()) { + Te T1 = Te(1.0), T2 = Te(2.0); + for (size_t i : exactIdx) { + leverage(diagP_exact, Le[i], A, At); + + Te *tau = diagP_exact.x.get(); + for (Ti j = 0; j < n; j++) + set(out[j], i, to_double(T1 - tau[j] * get(w[j], i))); + } + } + } + + void leverageScoreComplementJL(Tx2 *out, size_t JL_k) { + pcs_assert(decomposed, + "leverageScoreComplementJL: Need to call decompose first."); + + Ti m = A.m, n = A.n; + + if (!allExact()) { + Tx2 T1 = Tx2(1.0), T2 = Tx2(2.0); + leverageJL(diagPJL, L, A, At, JL_k); + + Tx2 *tau = diagPJL.x.get(); + for (Ti j = 0; j < n; j++) + out[j] = T1 - tau[j] * w[j]; + } + + if (hasExact()) { + Te T1 = Te(1.0), T2 = Te(2.0); + for (size_t i : exactIdx) { + leverageJL(diagPJL_exact, Le[i], A, At, JL_k); + + Te *tau = diagPJL_exact.x.get(); + for (Ti j = 0; j < n; j++) + set(out[j], i, to_double(T1 - tau[j] * get(w[j], i))); + } + } + } + + Tx2 estimateAccuracy() { + pcs_assert(decomposed, "estimateAccuracy: Need to call decompose first."); + + return cholAccuracy(diagPJL, L, A, At, w.get()); + } +}; diff --git a/external/PackedCSparse/SparseMatrix.h b/external/PackedCSparse/SparseMatrix.h new file mode 100644 index 000000000..5dca4286f --- /dev/null +++ b/external/PackedCSparse/SparseMatrix.h @@ -0,0 +1,230 @@ +// VolEsti (volume computation and sampling library) + +// Copyright (c) 2012-2018 Vissarion Fisikopoulos +// Copyright (c) 2018 Apostolos Chalkis +// Copyright (c) 2022 Ioannis Iakovidis + +// This file is converted from PolytopeSamplerMatlab +//(https://github.com/ConstrainedSampler/PolytopeSamplerMatlab/blob/master/code/solver/PackedCSparse/PackedChol.h) by Ioannis Iakovidis +#pragma once +#include +#include +#include "FloatArray.h" + +namespace PackedCSparse { + static void pcs_assert(bool value, const char* message) + { + if (value == false) + throw std::logic_error(message); + } + + template + T* pcs_aligned_new(size_t size) + { + int alignment = 64; // size of memory cache line + int offset = alignment - 1 + sizeof(void*); + void* p1 = (void*)new char[size * sizeof(T) + offset]; + void** p2 = (void**)(((size_t)(p1)+offset) & ~(alignment - 1)); + p2[-1] = p1; + return (T*)p2; + } + + template + struct AlignedDeleter + { + void operator()(T* p) const + { + delete[](char*)(((void**)p)[-1]); + } + }; + + template + using UniqueAlignedPtr = std::unique_ptr>; + + template + using UniquePtr = std::unique_ptr; + + // Tx = Type for entries, Ti = Type for indices. + // if Tx == bool, the matrix stores only sparsity information + template + struct SparseMatrix + { + Ti m = 0; /* number of rows */ + Ti n = 0; /* number of columns */ + UniquePtr p; /* column pointers (size n+1) */ + UniquePtr i; /* row indices, size nnz */ + UniqueAlignedPtr x; /* numerical values, size nnz */ + + SparseMatrix() = default; + + SparseMatrix(Ti m_, Ti n_, Ti nzmax_) + { + initialize(m_, n_, nzmax_); + } + + bool initialized() const + { + return p && i; + } + + void initialize(Ti m_, Ti n_, Ti nzmax) + { + if (nzmax < 1) nzmax = 1; + m = m_; n = n_; + p.reset(new Ti[n + 1]); + i.reset(new Ti[nzmax]); + if (!std::is_same::value) + x.reset(pcs_aligned_new(nzmax)); + } + + Ti nnz() const + { + return p[n]; + } + + template + SparseMatrix clone() const + { + SparseMatrix C(m, n, nnz()); + Ti* Ap = p.get(), * Ai = i.get(); Tx* Ax = x.get(); + Ti2* Cp = C.p.get(), * Ci = C.i.get(); Tx2* Cx = C.x.get(); + + for (Ti s = 0; s <= n; s++) + Cp[s] = Ti2(Ap[s]); + + Ti nz = nnz(); + for (Ti s = 0; s < nz; s++) + Ci[s] = Ti2(Ai[s]); + + if (Cx) + { + for (Ti s = 0; s < nz; s++) + Cx[s] = Ax? Tx2(Ax[s]): Tx2(1.0); + } + + return C; + } + }; + + template + struct DenseVector + { + Ti n = 0; /* number of columns */ + UniqueAlignedPtr x; /* numerical values, size nnz */ + + DenseVector() = default; + + DenseVector(Ti n_) + { + initialize(n_); + } + + bool initialized() const + { + return bool(x); + } + + void initialize(Ti n_) + { + n = n_; + x.reset(pcs_aligned_new(n_)); + } + }; + + + // basic functions + template + SparseMatrix speye(Ti n, Tx* d = nullptr) + { + SparseMatrix D(n, n, n); + + for (Ti k = 0; k < n; k++) + { + D.i[k] = k; + D.p[k] = k; + } + D.p[n] = n; + + Tx Tx1 = Tx(1.0); + for (Ti k = 0; k < n; k++) + D.x[k] = (d ? d[k] : Tx1); + return D; + } + + // Solve L out = x + // Input: L in Tx^{n by n}, x in Tx2^{n} + // Output: out in Tx2^{n}. + // If out is provided, we will output to out. Else, output to x. + template + void lsolve(const SparseMatrix& L, Tx2* x, Tx2* out = nullptr) + { + pcs_assert(L.initialized(), "lsolve: bad inputs."); + pcs_assert(L.n == L.m, "lsolve: dimensions mismatch."); + + Ti n = L.n, * Lp = L.p.get(), * Li = L.i.get(); Tx* Lx = L.x.get(); + + if (!out) out = x; + if (x != out) std::copy(x, x + n, out); + + for (Ti j = 0; j < n; j++) + { + Tx2 out_j = out[j] / Lx[Lp[j]]; + out[j] = out_j; + + Ti p_start = Lp[j] + 1, p_end = Lp[j + 1]; + for (Ti p = p_start; p < p_end; p++) + { //out[Li[p]] -= Lx[p] * out[j]; + fnmadd(out[Li[p]], out_j, Lx[p]); + } + } + } + + // Solve L' out = x + // Input: L in Tx^{n by n}, x in Tx2^{n} + // Output: out in Tx2^{n}. + // If out is provided, we will output to out. Else, output to x. + template + void ltsolve(const SparseMatrix& L, Tx2* x, Tx2* out = nullptr) + { + pcs_assert(L.initialized(), "ltsolve: bad inputs."); + pcs_assert(L.n == L.m, "ltsolve: dimensions mismatch."); + + Ti n = L.n, * Lp = L.p.get(), * Li = L.i.get(); Tx* Lx = L.x.get(); + + if (!out) out = x; + if (x != out) std::copy(x, x + n, out); + + for (Ti j = n - 1; j != -1; j--) + { + Tx2 out_j = out[j]; + + Ti p_start = Lp[j] + 1, p_end = Lp[j + 1]; + for (Ti p = p_start; p < p_end; p++) + { //out[j] -= Lx[p] * out[Li[p]]; + fnmadd(out_j, out[Li[p]], Lx[p]); + } + + out[j] = out_j / Tx2(Lx[Lp[j]]); + } + } + + // Update y <-- y + A x + // Input: A in Tx^{n by n}, x, y in Tx2^{n} + template + void gaxpy(const SparseMatrix& A, const Tx2* x, Tx2* y) + { + pcs_assert(A.initialized(), "gaxpy: bad inputs."); + Ti m = A.m, n = A.n, * Ap = A.p.get(), * Ai = A.i.get(); Tx* Ax = A.x.get(); + + for (Ti j = 0; j < n; j++) + { + Tx2 x_j = x[j]; + + Ti p_start = Ap[j], p_end = Ap[j + 1]; + for (Ti p = p_start; p < p_end; p++) + { //y[Ai[p]] += Ax[p] * x[j]; + fmadd(y[Ai[p]], x_j, Ax[p]); + } + } + } +}; diff --git a/external/PackedCSparse/add.h b/external/PackedCSparse/add.h new file mode 100644 index 000000000..161957226 --- /dev/null +++ b/external/PackedCSparse/add.h @@ -0,0 +1,102 @@ +// VolEsti (volume computation and sampling library) + +// Copyright (c) 2012-2018 Vissarion Fisikopoulos +// Copyright (c) 2018 Apostolos Chalkis +// Copyright (c) 2022 Ioannis Iakovidis + +// This file is converted from PolytopeSamplerMatlab +//(https://github.com/ConstrainedSampler/PolytopeSamplerMatlab/blob/master/code/solver/PackedCSparse/PackedChol.h) by Ioannis Iakovidis + +#pragma once +#include +#include "SparseMatrix.h" + +// Problem: +// Compute M = A + B + +// Algorithm: +// M = 0 +// M(A != 0) += A(A != 0) +// M(B != 0) += B(A != 0) + +namespace PackedCSparse { + template + struct AddOutput : SparseMatrix + { + UniquePtr forwardA; + UniquePtr forwardB; + + template + void initialize(const SparseMatrix& A, const SparseMatrix& B) + { + pcs_assert(A.initialized() && B.initialized(), "add: bad inputs."); + pcs_assert(A.n == B.n && A.m == B.m, "add: dimensions mismatch."); + + Ti m = A.m, n = A.n; + Ti Anz = A.nnz(); Ti* Ap = A.p.get(), * Ai = A.i.get(); + Ti Bnz = B.nnz(); Ti* Bp = B.p.get(), * Bi = B.i.get(); + this->m = A.m; this->n = A.n; + + std::vector Ci; + Ti* Cp = new Ti[n + 1]; + forwardA.reset(new Ti[Anz]); + forwardB.reset(new Ti[Bnz]); + + Cp[0] = 0; + for (Ti i = 0; i < n; i++) + { + Ti s1 = Ap[i], s2 = Bp[i], end1 = Ap[i + 1], end2 = Bp[i + 1]; + while ((s1 < end1) || (s2 < end2)) + { + Ti q = Ti(Ci.size()); + Ti i1 = (s1 < end1) ? Ai[s1] : m; + Ti i2 = (s2 < end2) ? Bi[s2] : m; + Ti min_i = std::min(i1, i2); + Ci.push_back(min_i); + + if (i1 == min_i) + forwardA[s1++] = q; + + if (i2 == min_i) + forwardB[s2++] = q; + } + Cp[i + 1] = Ti(Ci.size()); + } + + this->p.reset(Cp); + this->i.reset(new Ti[Ci.size()]); + this->x.reset(pcs_aligned_new(Ci.size())); + std::copy(Ci.begin(), Ci.end(), this->i.get()); + } + }; + + template + void add(AddOutput& o, const SparseMatrix& A, const SparseMatrix& B) + { + if (!o.initialized()) + o.initialize(A, B); + + Ti m = o.m, n = o.n; + Ti Anz = A.nnz(); Ti* Ap = A.p.get(), * Ai = A.i.get(); Tx* Ax = A.x.get(); + Ti Bnz = B.nnz(); Ti* Bp = B.p.get(), * Bi = B.i.get(); Tx* Bx = B.x.get(); + Ti Cnz = o.nnz(); Ti* Cp = o.p.get(), * Ci = o.i.get(); Tx2* Cx = o.x.get(); + Ti* forwardA = o.forwardA.get(), *forwardB = o.forwardB.get(); + + for (Ti s = 0; s < Cnz; s++) + Cx[s] = 0; + + for (Ti s = 0; s < Anz; s++) + Cx[forwardA[s]] = Ax[s]; + + for (Ti s = 0; s < Bnz; s++) + Cx[forwardB[s]] += Bx[s]; + } + + template + AddOutput add(const SparseMatrix& A, const SparseMatrix& B) + { + AddOutput o; + add(o, A, B); + return o; + } +} diff --git a/external/PackedCSparse/chol.h b/external/PackedCSparse/chol.h new file mode 100644 index 000000000..d6001ae2f --- /dev/null +++ b/external/PackedCSparse/chol.h @@ -0,0 +1,247 @@ +// VolEsti (volume computation and sampling library) + +// Copyright (c) 2012-2018 Vissarion Fisikopoulos +// Copyright (c) 2018 Apostolos Chalkis +// Copyright (c) 2022 Ioannis Iakovidis + +// This file is converted from PolytopeSamplerMatlab +//(https://github.com/ConstrainedSampler/PolytopeSamplerMatlab/blob/master/code/solver/PackedCSparse/PackedChol.h) by Ioannis Iakovidis + +#pragma once +#include +#include +#include "SparseMatrix.h" +#include "transpose.h" + +// Problem: +// Compute chol(A) + +// Algorithm: +// We need to study this later as this is the bottleneck. +// Document it as a lyx. +// chol_up_looking: +// Compute L row by row +// This is faster when it is compute bound. +// +// chol_left_looking: +// Compute L col by col +// This is faster when it is memory bound. + + +namespace PackedCSparse { + template + struct CholOutput : SparseMatrix + { + TransposeOutput Lt; // sparsity pattern of the Lt + UniquePtr diag; // the index for diagonal element. Ax[diag[k]] is A_kk + UniquePtr c; // c[i] = index the last nonzero on column i in the current L + UniqueAlignedPtr w; // the row of L we are computing + + // The cost of this is roughly 3 times larger than chol + // One can optimize it by using other data structure + void initialize(const SparseMatrix& A) + { + pcs_assert(A.initialized(), "chol: bad inputs."); + pcs_assert(A.n == A.m, "chol: dimensions mismatch."); + + Ti n = A.n, * Ap = A.p.get(), * Ai = A.i.get(); + + // initialize + this->diag.reset(new Ti[n]); + this->c.reset(new Ti[n]); + this->w.reset(pcs_aligned_new(n)); + + // compute the sparsity pattern of L and diag + using queue = std::priority_queue, std::greater>; + queue q; // sol'n of the current row of L + Ti* mark = new Ti[n]; // used to prevent same indices push to q twice + std::vector* cols = new std::vector[n]; // stores the non-zeros of each col of L + Ti nz = 0, Anz = Ap[n]; + + for (Ti i = 0; i < n; i++) + mark[i] = -1; + + // for each row of A + for (Ti i = 0; i < n; i++) + { // push i-th row of A, called a_12, into mark + Ti s; + for (s = Ap[i]; s < Ap[i + 1]; s++) + { + Ti j = Ai[s]; + if (j >= i) break; + + q.push(j); + mark[j] = i; + } + if (s >= Anz) // this case happens only if the diagonal is 0. No cholesky in this case. + this->diag[i] = 0; + else + this->diag[i] = s; + + // Solve L_11 l_12 = a_12 + while (!q.empty()) + { + Ti j = q.top(); + + for (Ti k : cols[j]) + { + if (mark[k] != i) + { + q.push(k); + mark[k] = i; + } + } + q.pop(); + + // update j col + cols[j].push_back(i); + ++nz; + } + + // diag + cols[i].push_back(i); + ++nz; + } + delete[] mark; + + // write it as the compress form + SparseMatrix::initialize(n, n, nz); + + Ti s_start = 0; Ti s = 0; + for (Ti i = 0; i < n; i++) + { + this->p[i] = s_start; + for (Ti k : cols[i]) + this->i[s++] = k; + s_start += Ti(cols[i].size()); + } + this->p[n] = s_start; + delete[] cols; + + this->Lt = transpose(*this); + + // initialize w to 0 + Tx Tv0 = Tx(0); + for (Ti k = 0; k < n; k++) + w[k] = Tv0; + } + }; + + template + void chol(CholOutput& o, const SparseMatrix& A) + { + if (!o.initialized()) + o.initialize(A); + + //chol_up_looking(o, A); + chol_left_looking(o, A); + } + + template + void chol_up_looking(CholOutput& o, const SparseMatrix& A) + { + Ti *Ap = A.p.get(), * Ai = A.i.get(); Tx* Ax = A.x.get(); + Ti nzmax = o.nzmax; Ti n = A.n; + Ti *Lp = o.p.get(); Ti* Li = o.i.get(); + Ti *Ltp = o.Lt.p.get(); Ti* Lti = o.Lt.i.get(); + + Tx T0 = Tx(0); + Tx* Lx = o.x.get(); Tx* w = o.w.get(); Ti* c = o.c.get(); + Ti* diag = o.diag.get(); + + Ti* Lti_ptr = Lti; + for (Ti k = 0; k < n; ++k) + { + c[k] = Lp[k]; + + Ti s_end = diag[k]; + for (Ti s = Ap[k]; s < s_end; ++s) + w[Ai[s]] = Ax[s]; + + // Solve L_11 l_12 = a_12 + Tx d = Ax[s_end]; Ti i; + for (; (i = *(Lti_ptr++)) < k;) + { + Ti dLi = Lp[i], ci = c[i]++; + Tx Lki = w[i] / Lx[dLi]; + w[i] = T0; // maintain x = 0 for the (k+1) iteration + + for (Ti q = dLi + 1; q < ci; ++q) + fnmadd(w[Li[q]], Lx[q], Lki); + + d -= Lki * Lki; + Lx[ci] = Lki; + } + + // l_22 = sqrt(a22 - ) + Lx[c[k]++] = clipped_sqrt(d); + } + } + + template + void chol_left_looking(CholOutput& o, const SparseMatrix& A) + { + Ti* Ap = A.p.get(), * Ai = A.i.get(); Tx* Ax = A.x.get(); + Ti nzmax = o.nnz(); Ti n = A.n; + Ti* Lp = o.p.get(); Ti* Li = o.i.get(); + Ti* Ltp = o.Lt.p.get(); Ti* Lti = o.Lt.i.get(); + + Tx T0 = Tx(0), T1 = Tx(1); + Tx* Lx = o.x.get(); + Tx* w = o.w.get(); Ti* c = o.c.get(); + Ti* diag = o.diag.get(); + + for (Ti j = 0; j < n; ++j) + { + c[j] = Lp[j]; + + // x = A_{j:n, j} + { + Ti is_start = diag[j], is_end = Ap[j + 1]; + for (Ti is = is_start; is < is_end; ++is) + w[Ai[is]] = Ax[is]; + } + + // for each p in L_{j, 1:j-1} + Ti ps_start = Ltp[j], ps_end = Ltp[j + 1] - 1; + for (Ti ps = ps_start; ps < ps_end; ++ps) + { + Ti p = Lti[ps]; + Ti cp = c[p]++; + Tx Ljp = Lx[cp]; + + // for each i in L_{j:n,p} + Ti is_start = cp, is_end = Lp[p + 1]; + for (Ti is = is_start; is < is_end; ++is) + { + Ti i = Li[is]; + fnmadd(w[i], Lx[is], Ljp); + } + } + + Tx Ljj = clipped_sqrt(w[j], 1e128); + Lx[c[j]++] = Ljj; + Tx inv_Ljj = T1 / Ljj; + w[j] = T0; + + // for each i in L_{:,j} + { + Ti is_start = Lp[j] + 1, is_end = Lp[j + 1]; + for (Ti is = is_start; is < is_end; ++is) + { + Ti i = Li[is]; + Lx[is] = w[i] * inv_Ljj; + w[i] = T0; + } + } + } + } + + template + CholOutput chol(const SparseMatrix& A) + { + CholOutput o; + chol(o, A); + return o; + } +} diff --git a/external/PackedCSparse/dd_real.h b/external/PackedCSparse/dd_real.h new file mode 100644 index 000000000..5fe3491e5 --- /dev/null +++ b/external/PackedCSparse/dd_real.h @@ -0,0 +1,303 @@ +// VolEsti (volume computation and sampling library) + +// Copyright (c) 2012-2018 Vissarion Fisikopoulos +// Copyright (c) 2018 Apostolos Chalkis +// Copyright (c) 2022 Ioannis Iakovidis + +// This file is converted from QD library +//(https://www.davidhbailey.com/dhbsoftware) by Ioannis Iakovidis + +/* + * include/dd_real.h + * + * This work was supported by the Director, Office of Science, Division + * of Mathematical, Information, and Computational Sciences of the + * U.S. Department of Energy under contract number DE-AC03-76SF00098. + * + * Copyright (c) 2000-2007 + * + * Double-double precision (>= 106-bit significand) floating point + * arithmetic package based on David Bailey's Fortran-90 double-double + * package, with some changes. See + * + * http://www.nersc.gov/~dhbailey/mpdist/mpdist.html + * + * for the original Fortran-90 version. + * + * Overall structure is similar to that of Keith Brigg's C++ double-double + * package. See + * + * http://www-epidem.plansci.cam.ac.uk/~kbriggs/doubledouble.html + * + * for more details. In particular, the fix for x86 computers is borrowed + * from his code. + * + * Yozo Hida + */ + +#ifndef _QD_DD_REAL_H +#define _QD_DD_REAL_H + +#include +#include +#include +#include +#include "qd/qd_config.h" +#include "qd/fpu.h" + +// Some compilers define isnan, isfinite, and isinf as macros, even for +// C++ codes, which cause havoc when overloading these functions. We undef +// them here. +#ifdef isnan +#undef isnan +#endif + +#ifdef isfinite +#undef isfinite +#endif + +#ifdef isinf +#undef isinf +#endif + +#ifdef max +#undef max +#endif + +#ifdef min +#undef min +#endif + +struct QD_API dd_real { + double x[2]; + inline operator bool() const // new + { + return (x[0] != 0.0); + + } + dd_real(double hi, double lo) { x[0] = hi; x[1] = lo; } + dd_real() {x[0] = 0.0; x[1] = 0.0; } + dd_real(double h) { x[0] = h; x[1] = 0.0; } + dd_real(int h) { + x[0] = (static_cast(h)); + x[1] = 0.0; + } + + dd_real (const char *s); + explicit dd_real (const double *d) { + x[0] = d[0]; x[1] = d[1]; + } + + static void error(const char *msg); + + double _hi() const { return x[0]; } + double _lo() const { return x[1]; } + + static const dd_real _2pi; + static const dd_real _pi; + static const dd_real _3pi4; + static const dd_real _pi2; + static const dd_real _pi4; + static const dd_real _e; + static const dd_real _log2; + static const dd_real _log10; + static const dd_real _nan; + static const dd_real _inf; + + static const double _eps; + static const double _min_normalized; + static const dd_real _max; + static const dd_real _safe_max; + static const int _ndigits; + + bool isnan() const { return QD_ISNAN(x[0]) || QD_ISNAN(x[1]); } + bool isfinite() const { return QD_ISFINITE(x[0]); } + bool isinf() const { return QD_ISINF(x[0]); } + + static dd_real add(double a, double b); + static dd_real ieee_add(const dd_real &a, const dd_real &b); + static dd_real sloppy_add(const dd_real &a, const dd_real &b); + + dd_real &operator+=(double a); + dd_real &operator+=(const dd_real &a); + + static dd_real sub(double a, double b); + + dd_real &operator-=(double a); + dd_real &operator-=(const dd_real &a); + + dd_real operator-() const; + + static dd_real mul(double a, double b); + + dd_real &operator*=(double a); + dd_real &operator*=(const dd_real &a); + + static dd_real div(double a, double b); + static dd_real sloppy_div(const dd_real &a, const dd_real &b); + static dd_real accurate_div(const dd_real &a, const dd_real &b); + + dd_real &operator/=(double a); + dd_real &operator/=(const dd_real &a); + + dd_real &operator=(double a); + dd_real &operator=(const char *s); + + dd_real operator^(int n); + static dd_real sqr(double d); + + static dd_real sqrt(double a); + + bool is_zero() const; + bool is_one() const; + bool is_positive() const; + bool is_negative() const; + + + static dd_real rand(void); + + void to_digits(char *s, int &expn, int precision = _ndigits) const; + void write(char *s, int len, int precision = _ndigits, + bool showpos = false, bool uppercase = false) const; + std::string to_string(int precision = _ndigits, int width = 0, + std::ios_base::fmtflags fmt = static_cast(0), + bool showpos = false, bool uppercase = false, char fill = ' ') const; + int read(const char *s, dd_real &a); + + /* Debugging Methods */ + void dump(const std::string &name, std::ostream &os = std::cerr) const; + void dump_bits(const std::string &name, + std::ostream &os = std::cerr) const; + + static dd_real debug_rand(); +}; + + +namespace std { + template <> + class numeric_limits : public numeric_limits { + public: + inline static double epsilon() { return dd_real::_eps; } + inline static dd_real max() { return dd_real::_max; } + inline static dd_real safe_max() { return dd_real::_safe_max; } + inline static double min() { return dd_real::_min_normalized; } + static const int digits = 104; + static const int digits10 = 31; + }; +} + +QD_API dd_real ddrand(void); +QD_API dd_real sqrt(const dd_real &a); + +QD_API dd_real polyeval(const dd_real *c, int n, const dd_real &x); +QD_API dd_real polyroot(const dd_real *c, int n, + const dd_real &x0, int max_iter = 32, double thresh = 0.0); + +QD_API inline bool isnan(const dd_real &a) { return a.isnan(); } +QD_API inline bool isfinite(const dd_real &a) { return a.isfinite(); } +QD_API inline bool isinf(const dd_real &a) { return a.isinf(); } + +/* Computes dd * d where d is known to be a power of 2. */ +QD_API dd_real mul_pwr2(const dd_real &dd, double d); + +QD_API dd_real operator+(const dd_real &a, double b); +QD_API dd_real operator+(double a, const dd_real &b); +QD_API dd_real operator+(const dd_real &a, const dd_real &b); + +QD_API dd_real operator-(const dd_real &a, double b); +QD_API dd_real operator-(double a, const dd_real &b); +QD_API dd_real operator-(const dd_real &a, const dd_real &b); + +QD_API dd_real operator*(const dd_real &a, double b); +QD_API dd_real operator*(double a, const dd_real &b); +QD_API dd_real operator*(const dd_real &a, const dd_real &b); + +QD_API dd_real operator/(const dd_real &a, double b); +QD_API dd_real operator/(double a, const dd_real &b); +QD_API dd_real operator/(const dd_real &a, const dd_real &b); + +QD_API dd_real inv(const dd_real &a); + +QD_API dd_real rem(const dd_real &a, const dd_real &b); +QD_API dd_real drem(const dd_real &a, const dd_real &b); +QD_API dd_real divrem(const dd_real &a, const dd_real &b, dd_real &r); + +QD_API dd_real pow(const dd_real &a, int n); +QD_API dd_real pow(const dd_real &a, const dd_real &b); +QD_API dd_real npwr(const dd_real &a, int n); +QD_API dd_real sqr(const dd_real &a); + +QD_API dd_real sqrt(const dd_real &a); +QD_API dd_real nroot(const dd_real &a, int n); + +QD_API bool operator==(const dd_real &a, double b); +QD_API bool operator==(double a, const dd_real &b); +QD_API bool operator==(const dd_real &a, const dd_real &b); + +QD_API bool operator<=(const dd_real &a, double b); +QD_API bool operator<=(double a, const dd_real &b); +QD_API bool operator<=(const dd_real &a, const dd_real &b); + +QD_API bool operator>=(const dd_real &a, double b); +QD_API bool operator>=(double a, const dd_real &b); +QD_API bool operator>=(const dd_real &a, const dd_real &b); + +QD_API bool operator<(const dd_real &a, double b); +QD_API bool operator<(double a, const dd_real &b); +QD_API bool operator<(const dd_real &a, const dd_real &b); + +QD_API bool operator>(const dd_real &a, double b); +QD_API bool operator>(double a, const dd_real &b); +QD_API bool operator>(const dd_real &a, const dd_real &b); + +QD_API bool operator!=(const dd_real &a, double b); +QD_API bool operator!=(double a, const dd_real &b); +QD_API bool operator!=(const dd_real &a, const dd_real &b); + +QD_API dd_real nint(const dd_real &a); +QD_API dd_real floor(const dd_real &a); +QD_API dd_real ceil(const dd_real &a); +QD_API dd_real aint(const dd_real &a); + +QD_API dd_real ddrand(void); + +double to_double(const dd_real &a); +int to_int(const dd_real &a); + +QD_API dd_real exp(const dd_real &a); +QD_API dd_real ldexp(const dd_real &a, int exp); +QD_API dd_real log(const dd_real &a); +QD_API dd_real log10(const dd_real &a); + +QD_API dd_real sin(const dd_real &a); +QD_API dd_real cos(const dd_real &a); +QD_API dd_real tan(const dd_real &a); +QD_API void sincos(const dd_real &a, dd_real &sin_a, dd_real &cos_a); + +QD_API dd_real asin(const dd_real &a); +QD_API dd_real acos(const dd_real &a); +QD_API dd_real atan(const dd_real &a); +QD_API dd_real atan2(const dd_real &y, const dd_real &x); + +QD_API dd_real sinh(const dd_real &a); +QD_API dd_real cosh(const dd_real &a); +QD_API dd_real tanh(const dd_real &a); +QD_API void sincosh(const dd_real &a, + dd_real &sinh_a, dd_real &cosh_a); + +QD_API dd_real asinh(const dd_real &a); +QD_API dd_real acosh(const dd_real &a); +QD_API dd_real atanh(const dd_real &a); + +QD_API dd_real fabs(const dd_real &a); +QD_API dd_real abs(const dd_real &a); /* same as fabs */ + +QD_API dd_real fmod(const dd_real &a, const dd_real &b); + +QD_API std::ostream& operator<<(std::ostream &s, const dd_real &a); +QD_API std::istream& operator>>(std::istream &s, dd_real &a); +#ifdef QD_INLINE +#include "qd/dd_inline.h" +#endif + +#endif /* _QD_DD_REAL_H */ diff --git a/external/PackedCSparse/leverage.h b/external/PackedCSparse/leverage.h new file mode 100644 index 000000000..695493086 --- /dev/null +++ b/external/PackedCSparse/leverage.h @@ -0,0 +1,65 @@ +// VolEsti (volume computation and sampling library) + +// Copyright (c) 2012-2018 Vissarion Fisikopoulos +// Copyright (c) 2018 Apostolos Chalkis +// Copyright (c) 2022 Ioannis Iakovidis + +// This file is converted from PolytopeSamplerMatlab +//(https://github.com/ConstrainedSampler/PolytopeSamplerMatlab/blob/master/code/solver/PackedCSparse/PackedChol.h) by Ioannis Iakovidis + +#pragma once +#include "SparseMatrix.h" +#include "projinv.h" +#include "outerprod.h" + +// Problem: +// Compute M = diag(A' inv(LL') A) + +namespace PackedCSparse { + template + struct LeverageOutput : DenseVector + { + ProjinvOutput Hinv; // Hinv = inv(H)|_L + OuterprodOutput tau; // tau = diag(A' Hinv A) + + template + void initialize(const SparseMatrix& L, const SparseMatrix& A, const SparseMatrix& At) + { + pcs_assert(L.initialized() && A.initialized() && At.initialized(), "leverage: bad inputs."); + pcs_assert(L.m == L.n && L.n == A.m && L.n == At.n && A.n == At.m, "leverage: dimensions mismatch."); + DenseVector::initialize(A.n); + Hinv.initialize(L); + tau.initialize(A, Hinv, At); + } + }; + + template + void leverage(LeverageOutput& o, const SparseMatrix& L, const SparseMatrix& A, const SparseMatrix& At) + { + if (!o.initialized()) + o.initialize(L, A, At); + + Tx T1 = Tx(1.0), T2 = Tx(2.0); + projinv(o.Hinv, L); + + Ti m = A.m, n = A.n; + Ti* Sp = o.Hinv.p.get(); Tx* Sv = o.Hinv.x.get(); + for (Ti k = 0; k < m; ++k) + Sv[Sp[k]] /= T2; + + outerprod(o.tau, A, o.Hinv, At); + + Tx* x = o.x.get(), * tau = o.tau.x.get(); + for (Ti j = 0; j < n; j++) + x[j] = T2 * tau[j]; + } + + + template + LeverageOutput leverage(const SparseMatrix& L, const SparseMatrix& A, const SparseMatrix& At) + { + LeverageOutput o; + leverage(o, L, A, At); + return o; + } +} diff --git a/external/PackedCSparse/leverageJL.h b/external/PackedCSparse/leverageJL.h new file mode 100644 index 000000000..a5001bcd4 --- /dev/null +++ b/external/PackedCSparse/leverageJL.h @@ -0,0 +1,148 @@ +// VolEsti (volume computation and sampling library) + +// Copyright (c) 2012-2018 Vissarion Fisikopoulos +// Copyright (c) 2018 Apostolos Chalkis +// Copyright (c) 2022 Ioannis Iakovidis + +// This file is converted from PolytopeSamplerMatlab +//(https://github.com/ConstrainedSampler/PolytopeSamplerMatlab/blob/master/code/solver/PackedCSparse/PackedChol.h) by Ioannis Iakovidis + +#pragma once +#include +#include "SparseMatrix.h" + +// Problem: +// Approximate M = diag(A' inv(LL') A) +namespace PackedCSparse { + const size_t JLPackedSize = 4; + + template + struct LeverageJLOutput : DenseVector + { + UniqueAlignedPtr d; // random direction d + UniqueAlignedPtr L_d; // random direction d + UniqueAlignedPtr AtL_d; // A' L^{-1} d + Ti m = 0; + std::mt19937_64 gen; + + template + void initialize(const SparseMatrix& L, const SparseMatrix& A, const SparseMatrix& At) + { + pcs_assert(L.initialized() && A.initialized() && At.initialized(), "leverageJL: bad inputs."); + pcs_assert(L.m == L.n && L.n == A.m && L.n == At.n && A.n == At.m, "leverageJL: dimensions mismatch."); + this->n = A.n; this->m = A.m; + this->x.reset(pcs_aligned_new(this->n)); + this->d.reset(pcs_aligned_new(this->m * 2 * JLPackedSize)); + this->L_d.reset(pcs_aligned_new(this->m * 2 * JLPackedSize)); + this->AtL_d.reset(pcs_aligned_new(this->n * 2 * JLPackedSize)); + } + }; + + // compute sum_{j=1}^{k} (A' L^{-T} u_j) .* (A' L^{-T} u_j) + template + void projectionJL(LeverageJLOutput& o, const SparseMatrix& L, const SparseMatrix& A, const SparseMatrix& At) + { + Ti m = A.m, n = A.n; + Tx T0 = Tx(0.0), T1 = Tx(1.0); + Tx* d = o.d.get(), * L_d = o.L_d.get(), * AtL_d = o.AtL_d.get(), * x = o.x.get(); + + for (Ti i = 0; i < m * k; i++) + d[i] = sign(o.gen); + + for (Ti i = 0; i < n * k; i++) + AtL_d[i] = T0; + + ltsolve(L, (BaseImpl*)d, (BaseImpl*)L_d); + gaxpy(At, (BaseImpl*)L_d, (BaseImpl*)AtL_d); + + for (Ti i = 0; i < n; i++) + { + Tx ret_i = T0; + for (Ti j = 0; j < k; j++) + ret_i += AtL_d[i * k + j] * AtL_d[i * k + j]; + + x[i] += ret_i; + } + } + + template + void leverageJL(LeverageJLOutput& o, const SparseMatrix& L, const SparseMatrix& A, const SparseMatrix& At, size_t k) + { + if (!o.initialized()) + o.initialize(L, A, At); + + Ti n = A.n; Tx* x = o.x.get(); + for (Ti i = 0; i < n; i++) + x[i] = Tx(0.0); + + constexpr size_t k_step = JLPackedSize; + for(size_t i = 1; i <= k / k_step; i++) + projectionJL(o, L, A, At); + + for (size_t i = 1; i <= k % k_step; i++) + projectionJL<1>(o, L, A, At); + + Tx ratio = Tx(1 / double(k)); + for (Ti i = 0; i < n; i++) + x[i] *= ratio; + } + + template + LeverageJLOutput leverageJL(const SparseMatrix& L, const SparseMatrix& A, const SparseMatrix& At, size_t k) + { + LeverageJLOutput o; + leverageJL(o, L, A, At, k); + return o; + } + + + // compute (A' L^{-T} u_j) .* (A' L^{-T} v_j) for j = 1, 2, ... k + template + Tx cholAccuracy(LeverageJLOutput& o, const SparseMatrix& L, const SparseMatrix& A, const SparseMatrix& At, const Tx* w) + { + if (!o.initialized()) + o.initialize(L, A, At); + + constexpr Ti k = JLPackedSize; + constexpr Ti k_ = 2 * k; + + + Ti m = A.m, n = A.n; + Tx T0 = Tx(0.0), T1 = Tx(1.0); + Tx* d = o.d.get(), * L_d = o.L_d.get(), * AtL_d = o.AtL_d.get(), * x = o.x.get(); + + std::uniform_real_distribution distribution(-sqrt(3.0),sqrt(3.0)); + for (Ti i = 0; i < m * k_; i++) + d[i] = Tx(distribution(o.gen)); // roughly uniform distribution with variance 1 + + for (Ti i = 0; i < n * k_; i++) + AtL_d[i] = T0; + + ltsolve(L, (BaseImpl*)d, (BaseImpl*)L_d); + gaxpy(At, (BaseImpl*)L_d, (BaseImpl*)AtL_d); + + Tx result[k]; + for (Ti j = 0; j < k; j++) + result[j] = Tx(0.0); + + for (Ti i = 0; i < m; i++) + { + Tx* d = o.d.get() + i * (2 * k); + for (Ti j = 0; j < k; j++) + result[j] -= d[j] * d[j + k]; + } + + for (Ti i = 0; i < n; i++) + { + Tx w_i = w[i]; + for (Ti j = 0; j < k; j++) + result[j] += AtL_d[i * k_ + j] * AtL_d[i * k_ + j + k] * w_i; + } + + Tx est = Tx(0.0); + for (Ti j = 0; j < k; j++) + est += result[j] * result[j]; + + return clipped_sqrt(est/Tx(double(k)), 0.0); + } +} diff --git a/external/PackedCSparse/multiply.h b/external/PackedCSparse/multiply.h new file mode 100644 index 000000000..cfd53375c --- /dev/null +++ b/external/PackedCSparse/multiply.h @@ -0,0 +1,142 @@ +// VolEsti (volume computation and sampling library) + +// Copyright (c) 2012-2018 Vissarion Fisikopoulos +// Copyright (c) 2018 Apostolos Chalkis +// Copyright (c) 2022 Ioannis Iakovidis + +// This file is converted from PolytopeSamplerMatlab +//(https://github.com/ConstrainedSampler/PolytopeSamplerMatlab/blob/master/code/solver/PackedCSparse/PackedChol.h) by Ioannis Iakovidis + +#pragma once +#include +#include +#include "SparseMatrix.h" + +// Problem: +// Compute M = A diag(w) B + +// Algorithm: +// Compute M col by col + +namespace PackedCSparse { + template + struct MultiplyOutput : SparseMatrix + { + UniqueAlignedPtr c; + + template + void initialize(const SparseMatrix& A, const SparseMatrix& B) + { + pcs_assert(A.initialized() && B.initialized(), "multiply: bad inputs."); + pcs_assert(A.n == B.m, "multiply: dimensions mismatch."); + + Ti m = A.m, n = B.n; + Ti* Ap = A.p.get(), * Ai = A.i.get(); + Ti* Bp = B.p.get(), * Bi = B.i.get(); + + this->c.reset(pcs_aligned_new(m)); + + Ti* last_j = new Ti[m]; + for (Ti i = 0; i < m; i++) + { + last_j[i] = -1; + this->c[i] = Tx(0.0); + } + + Ti* Cp = new Ti[size_t(n)+1]; + std::vector Ci; + + Cp[0] = 0; + for (Ti j1 = 0; j1 < n; j1++) + { + for (Ti p1 = Bp[j1]; p1 < Bp[j1 + 1]; p1++) + { + Ti j2 = Bi[p1]; + for (Ti p2 = Ap[j2]; p2 < Ap[j2 + 1]; p2++) + { + Ti i = Ai[p2]; + if (last_j[i] != j1) + { + last_j[i] = j1; + Ci.push_back(i); + } + } + } + Cp[j1 + 1] = Ti(Ci.size()); + } + delete[] last_j; + + for (Ti j = 0; j < n; j++) + std::sort(Ci.begin() + Cp[j], Ci.begin() + Cp[j + 1]); + + this->m = m; this->n = n; + this->x.reset(pcs_aligned_new(Ci.size())); + this->p.reset(Cp); + this->i.reset(new Ti[Ci.size()]); + std::copy(Ci.begin(), Ci.end(), this->i.get()); + } + }; + + template + void multiply_general(MultiplyOutput& o, const SparseMatrix& A, const Tx2* w, const SparseMatrix& B) + { + if (!o.initialized()) + o.initialize(A, B); + + Ti m = o.m, n = o.n; + Ti* Ap = A.p.get(), * Ai = A.i.get(); Tx* Ax = A.x.get(); + Ti* Bp = B.p.get(), * Bi = B.i.get(); Tx* Bx = B.x.get(); + Ti* Cp = o.p.get(), * Ci = o.i.get(); Tx2* Cx = o.x.get(); + Tx2* c = o.c.get(); // initialized to 0 + + const Tx2 T0 = Tx2(0); + for (Ti j1 = 0; j1 < n; j1++) + { + for (Ti p1 = Bp[j1]; p1 < Bp[j1 + 1]; p1++) + { + Ti j2 = Bi[p1]; + Tx2 beta = has_weight? (Tx2(Bx[p1]) * w[j2]) : Tx2(Bx[p1]); + + for (Ti p2 = Ap[j2]; p2 < Ap[j2 + 1]; p2++) + { + //x[Ai[p2]] += beta * Ax[p2]; + fmadd(c[Ai[p2]], beta, Ax[p2]); + } + } + + for (Ti p1 = Cp[j1]; p1 < Cp[j1 + 1]; p1++) + { + Cx[p1] = c[Ci[p1]]; + c[Ci[p1]] = T0; // ensure c is 0 after the call + } + } + } + + template + void multiply(MultiplyOutput& o, const SparseMatrix& A, const SparseMatrix& B) + { + multiply_general(o, A, nullptr, B); + } + + template + void multiply(MultiplyOutput& o, const SparseMatrix& A, const Tx2* w, const SparseMatrix& B) + { + multiply_general(o, A, w, B); + } + + template + MultiplyOutput multiply(const SparseMatrix& A, const Tx2* w, const SparseMatrix& B) + { + MultiplyOutput o; + multiply(o, A, w, B); + return o; + } + + template + MultiplyOutput multiply(const SparseMatrix& A, const SparseMatrix& B) + { + MultiplyOutput o; + multiply(o, A, B); + return o; + } +} diff --git a/external/PackedCSparse/outerprod.h b/external/PackedCSparse/outerprod.h new file mode 100644 index 000000000..6f0e98e39 --- /dev/null +++ b/external/PackedCSparse/outerprod.h @@ -0,0 +1,86 @@ +// VolEsti (volume computation and sampling library) + +// Copyright (c) 2012-2018 Vissarion Fisikopoulos +// Copyright (c) 2018 Apostolos Chalkis +// Copyright (c) 2022 Ioannis Iakovidis + +// This file is converted from PolytopeSamplerMatlab +//(https://github.com/ConstrainedSampler/PolytopeSamplerMatlab/blob/master/code/solver/PackedCSparse/PackedChol.h) by Ioannis Iakovidis +#pragma once +#include "SparseMatrix.h" + +// Problem: +// Compute x = diag(At S Bt) + +// Algorithm: +// Note that x = diag(B St A) = grad_H Tr(St A H B) +// We run autodiff on the function Tr(St A H B). +// Hence, the algorithm is essentially same as multiply(A, B) with the same runtime. + +namespace PackedCSparse { + template + struct OuterprodOutput : DenseVector + { + UniqueAlignedPtr s_col; + UniquePtr s_mark; + + template + void initialize(const SparseMatrix& A, const SparseMatrix& S, const SparseMatrix& B) + { + pcs_assert(A.initialized() && B.initialized() && S.initialized(), "outerprod: bad inputs."); + pcs_assert(A.m == S.m && S.n == B.n, "outerprod: dimensions mismatch."); + + DenseVector::initialize(A.n); + s_col.reset(pcs_aligned_new(S.m)); + s_mark.reset(new Ti[S.m]); + } + }; + + template + void outerprod(OuterprodOutput& o, const SparseMatrix& A, const SparseMatrix& S, const SparseMatrix& B) + { + if (!o.initialized()) + o.initialize(A, S, B); + + Ti Sn = S.n, Sm = S.m, An = A.n; + Ti* Ap = A.p.get(), * Ai = A.i.get(); Tx2* Ax = A.x.get(); + Ti* Bp = B.p.get(), * Bi = B.i.get(); Tx2* Bx = B.x.get(); + Ti* Sp = S.p.get(), * Si = S.i.get(); Tx* Sx = S.x.get(); + Tx* s_col = o.s_col.get(); + Ti* s_mark = o.s_mark.get(); + Tx* x = o.x.get(); + + std::fill(s_mark, s_mark + Sm, Ti(-1)); + std::fill(x, x + An, Tx(0.0)); + + for (Ti j = 0; j < Sn; j++) + { + for (Ti p = Sp[j]; p < Sp[j + 1]; p++) + { + s_col[Si[p]] = Sx[p]; + s_mark[Si[p]] = j; + } + + for (Ti p = Bp[j]; p < Bp[j + 1]; p++) + { + Ti i = Bi[p]; Tx b = Bx[p]; + for (Ti q = Ap[i]; q < Ap[i + 1]; q++) + { + Tx a = Ax[q]; Ti a_i = Ai[q]; + if (s_mark[a_i] == j) + { //x[i] += s_col[a_i] * a * b; + fmadd(x[i], s_col[a_i], a * b); + } + } + } + } + } + + template + OuterprodOutput outerprod(const SparseMatrix& A, const SparseMatrix& S, const SparseMatrix& B) + { + OuterprodOutput o; + outerprod(o, A, S, B); + return o; + } +} diff --git a/external/PackedCSparse/projinv.h b/external/PackedCSparse/projinv.h new file mode 100644 index 000000000..a319a47ea --- /dev/null +++ b/external/PackedCSparse/projinv.h @@ -0,0 +1,90 @@ +// VolEsti (volume computation and sampling library) + +// Copyright (c) 2012-2018 Vissarion Fisikopoulos +// Copyright (c) 2018 Apostolos Chalkis +// Copyright (c) 2022 Ioannis Iakovidis + +// This file is converted from PolytopeSamplerMatlab +//(https://github.com/ConstrainedSampler/PolytopeSamplerMatlab/blob/master/code/solver/PackedCSparse/PackedChol.h) by Ioannis Iakovidis + +#pragma once +#include "SparseMatrix.h" + +// Problem: +// Compute inv(L L') restricted on L + +// Algorithm: +// We need to study this later as this is the bottleneck. +// Document it as a lyx. + +namespace PackedCSparse { + template + struct ProjinvOutput : SparseMatrix + { + TransposeOutput Lt; // sparsity pattern of the Lt + UniqueAlignedPtr w; // the row of L we are computing + UniquePtr c; // c[i] = index the last nonzero on column i in the current L + + void initialize(const SparseMatrix& L) + { + pcs_assert(L.initialized(), "chol: bad inputs."); + pcs_assert(L.n == L.m, "chol: dimensions mismatch."); + + // Copy the sparsity of L + SparseMatrix::operator=(std::move(L.clone())); + + // allocate workspaces + Ti n = L.n; + w.reset(pcs_aligned_new(n)); + c.reset(new Ti[n]); + Lt = transpose(L); + } + }; + + template + void projinv(ProjinvOutput& o, const SparseMatrix& L) + { + if (!o.initialized()) + o.initialize(L); + + Tx* Sx = o.x.get(); Ti n = o.n; + Ti* Li = L.i.get(), * Lp = L.p.get(); Tx* Lv = L.x.get(); + Ti* Lti = o.Lt.i.get(), * Ltp = o.Lt.p.get(); + Tx* w = o.w.get(); + Ti* c = o.c.get(); + Tx T0 = Tx(0), T1 = Tx(1); + + for (Ti k = 0; k < n; k++) + c[k] = Lp[k + 1] - 1; + + for (Ti k = n - 1; k != -1; k--) + { + for (Ti p = Lp[k] + 1; p < Lp[k + 1]; p++) + w[Li[p]] = Sx[p]; + + Tx sum = T1 / Lv[Lp[k]]; + for (Ti p = Ltp[k + 1] - 1; p != Ltp[k] - 1; p--) + { + Ti i = Lti[p], Lpi = Lp[i]; + + for (Ti q = Lp[i + 1] - 1; q != Lpi; q--) + fnmadd(sum, Lv[q], w[Li[q]]); + //sum -= Lv[q] * w[Li[q]]; + + sum = sum / Lv[Lpi]; + w[i] = sum; + Sx[c[i]] = sum; + c[i]--; + sum = T0; + } + } + } + + template + ProjinvOutput projinv(const SparseMatrix& L) + { + ProjinvOutput o; + projinv(o, L); + return o; + } +} diff --git a/external/PackedCSparse/transpose.h b/external/PackedCSparse/transpose.h new file mode 100644 index 000000000..6e1502e31 --- /dev/null +++ b/external/PackedCSparse/transpose.h @@ -0,0 +1,90 @@ +// VolEsti (volume computation and sampling library) + +// Copyright (c) 2012-2018 Vissarion Fisikopoulos +// Copyright (c) 2018 Apostolos Chalkis +// Copyright (c) 2022 Ioannis Iakovidis + +// This file is converted from PolytopeSamplerMatlab +//(https://github.com/ConstrainedSampler/PolytopeSamplerMatlab/blob/master/code/solver/PackedCSparse/PackedChol.h) by Ioannis Iakovidis +#pragma once +#include "SparseMatrix.h" + +// Problem: +// Compute M = A' + +// Algorithm: +// We precompute the mapping from entries of A to entries of At + +namespace PackedCSparse { + template + struct TransposeOutput : SparseMatrix + { + UniquePtr forward; + + template + void initialize(const SparseMatrix& A) + { + pcs_assert(A.initialized(), "transpose: bad inputs."); + SparseMatrix::initialize(A.n, A.m, A.nnz()); + + Ti Am = A.m, An = A.n, * Ap = A.p.get(), * Ai = A.i.get(); + Ti Bm = this->m, Bn = this->n, * Bp = this->p.get(), * Bi = this->i.get(); + Ti nz = A.nnz(); + + // compute row counts of A + Ti* count = new Ti[Bn + 1](); + + for (Ti p = 0; p < nz; p++) + count[Ai[p]]++; + + // compute this->p + Bp[0] = 0; + for (Ti i = 0; i < Bn; i++) + { + Bp[i + 1] = Bp[i] + count[i]; + count[i] = Bp[i]; // Now, cnt[i] stores the index of the first element in the i-th row + } + + // compute i and forward + if (!std::is_same::value) + forward.reset(new Ti[nz]); + for (Ti j = 0; j < An; j++) + { + for (Ti p = Ap[j]; p < Ap[j + 1]; p++) + { + Ti q = count[Ai[p]]; + Bi[q] = j; + if (!std::is_same::value) + forward[p] = q; + count[Ai[p]]++; + } + } + + delete[] count; + } + }; + + template + void transpose(TransposeOutput& o, const SparseMatrix& A) + { + if (!o.initialized()) + o.initialize(A); + + Tx* Ax = A.x.get(); Tx2 *Bx = o.x.get(); + Ti nz = o.nnz(), *forward = o.forward.get(); + + if (!std::is_same::value) + { + for (Ti s = 0; s < nz; s++) + Bx[forward[s]] = Tx2(Ax[s]); + } + } + + template + TransposeOutput transpose(const SparseMatrix& A) + { + TransposeOutput o; + transpose(o, A); + return o; + } +} diff --git a/external/cmake-files/QD.cmake b/external/cmake-files/QD.cmake new file mode 100644 index 000000000..b65e4f51c --- /dev/null +++ b/external/cmake-files/QD.cmake @@ -0,0 +1,54 @@ +set(QD_CMAKE_DIR ${CMAKE_CURRENT_LIST_DIR}) +function(GetQD) + find_path(QD_DIR NAMES config.h PATHS ${QD_CMAKE_DIR}/../_deps/qd-src/) + + if (NOT QD_DIR) + include(FetchContent) + set(FETCHCONTENT_BASE_DIR "${QD_CMAKE_DIR}/../_deps") + FetchContent_Declare( + qd + URL https://www.davidhbailey.com/dhbsoftware/qd-2.3.23.tar.gz + ) + + FetchContent_GetProperties(qd) + + if(NOT qd_POPULATED) + message(STATUS "QD library not found locally, downloading it.") + FetchContent_Populate(qd) + endif() + + set(QD_DIR "${qd_SOURCE_DIR}") + message(STATUS "Using downloaded QD at: ${QD_DIR}") + + else() + + message(STATUS "QD library found: ${QD_DIR}") + + endif() + + include_directories(BEFORE "${QD_DIR}/include/") + message(STATUS "configuring the QD library") + execute_process( + COMMAND ./configure + WORKING_DIRECTORY ${QD_DIR} + OUTPUT_FILE CMD_OUTPUT + RESULT_VARIABLE EXECUTE + ) + if(NOT ${EXECUTE} EQUAL "0") + message(FATAL_ERROR "./configure QD library failed") + endif() + + execute_process( + COMMAND make + WORKING_DIRECTORY ${QD_DIR} + OUTPUT_FILE qd_compilation.txt + RESULT_VARIABLE EXECUTE_MAKE + ) + + if(NOT ${EXECUTE_MAKE} EQUAL "0") + message(FATAL_ERROR "building the QD library failed") + endif() + + find_library(QD_LIB NAMES libqd.a PATHS "${QD_DIR}/src/.libs") + +endfunction() diff --git a/include/ode_solvers/oracle_functors.hpp b/include/ode_solvers/oracle_functors.hpp index ff0fddbfa..3c0ac1eae 100644 --- a/include/ode_solvers/oracle_functors.hpp +++ b/include/ode_solvers/oracle_functors.hpp @@ -343,6 +343,10 @@ struct GaussianFunctor { return xs[i + 1]; // returns derivative } } + Point operator()(Point const&x){ + Point y = (-2.0 * params.a) * (x - params.x0); + return y; + } }; @@ -365,6 +369,24 @@ struct GaussianFunctor { }; + template +< + typename Point +> +struct HessianFunctor { + typedef typename Point::FT NT; + + parameters ¶ms; + + HessianFunctor(parameters ¶ms_) : params(params_) {}; + + // The index i represents the state vector index + Point operator() (Point const& x) const { + return (2.0 * params.a) * Point::all_ones(x.dimension()); + } + +}; + }; #endif diff --git a/include/preprocess/crhmc/analytic_center.h b/include/preprocess/crhmc/analytic_center.h new file mode 100644 index 000000000..35d4349aa --- /dev/null +++ b/include/preprocess/crhmc/analytic_center.h @@ -0,0 +1,178 @@ +// VolEsti (volume computation and sampling library) + +// Copyright (c) 2012-2020 Vissarion Fisikopoulos +// Copyright (c) 2018-2020 Apostolos Chalkis +// Copyright (c) 2022-2022 Ioannis Iakovidis + +// Contributed and/or modified by Ioannis Iakovidis, as part of Google Summer of +// Code 2022 program. + +// Licensed under GNU LGPL.3, see LICENCE file + +// References +// Yunbum Kook, Yin Tat Lee, Ruoqi Shen, Santosh S. Vempala. "Sampling with +// Riemannian Hamiltonian +// Monte Carlo in a Constrained Space" +#ifndef ANALYTIC_CENTER_H +#define ANALYTIC_CENTER_H +#include "Eigen/Eigen" +#include "PackedCSparse/PackedChol.h" +#include "preprocess/crhmc/crhmc_utils.h" +#include "preprocess/crhmc/opts.h" +#include +#include +#include +#ifndef SIMD_LEN +#define SIMD_LEN 0 +#endif +const size_t chol_k2 = (SIMD_LEN == 0) ? 1 : SIMD_LEN; + +using NT = double; +using MT = Eigen::Matrix; +using VT = Eigen::Matrix; +using SpMat = Eigen::SparseMatrix; +using CholObj = PackedChol; +using Triple = Eigen::Triplet; +using Tx = FloatArray; +using Opts = opts; +/*This function computes the analytic center of the polytope*/ +//And detects additional constraint that need to be added +// x - It outputs the minimizer of min f(x) subjects to {Ax=b} +// C - detected constraint matrix +// If the domain ({Ax=b} intersect dom(f)) is not full dimensional in {Ax=b} +// because of the dom(f), the algorithm will detect the collapsed dimension +// and output the detected constraint C x = d +// d - detected constraint vector +template +std::tuple analytic_center(SpMat const &A, VT const &b, Polytope &f, Opts const &options, VT x = VT::Zero(0, 1)) +{ + // initial conditions + int n = A.cols(); + int m = A.rows(); + if (x.rows() == 0 || !f.barrier.feasible(x)) + { + x = f.barrier.center; + } + + VT lambda = VT::Zero(n, 1); + int fullStep = 0; + NT tConst = 0; + NT primalErr = std::numeric_limits::max(); + NT dualErr = std::numeric_limits::max(); + NT primalErrMin = std::numeric_limits::max(); + NT primalFactor = 1; + NT dualFactor = 1 + b.norm(); + std::vector idx; + + CholObj solver = CholObj(transform_format(A)); + + for (int iter = 0; iter < options.ipmMaxIter; iter++) + { + std::pair pair_analytic_oracle = f.analytic_center_oracle(x); + VT grad = pair_analytic_oracle.first; + VT hess = pair_analytic_oracle.second; + + // compute the residual + VT rx = lambda - grad; + VT rs = b - A * x; + + // check stagnation + primalErrMin = std::min(primalErr, primalErrMin); + primalErr = rx.norm() / primalFactor; + NT dualErrLast = dualErr; + dualErr = rs.norm() / dualFactor; + bool feasible = f.barrier.feasible(x); + //Compare the dual and primal error to the last and minimum so far + if ((dualErr > (1 - 0.9 * tConst) * dualErrLast) || + (primalErr > 10 * primalErrMin) || !feasible) + { + VT dist = f.barrier.boundary_distance(x); + NT th = options.ipmDistanceTol; + visit_lambda(dist, [&idx, th](double v, int i, int j) + { + if (v < th) + idx.push_back(i); }); + if (idx.size() > 0) + { + break; + } + } + + // compute the step direction + VT Hinv = hess.cwiseInverse(); + solver.decompose((Tx *)Hinv.data()); + VT out(m, 1); + solver.solve((Tx *)rs.data(), (Tx *)out.data()); + VT dr1 = A.transpose() * out; + VT in = A * Hinv.cwiseProduct(rx); + solver.solve((Tx *)in.data(), (Tx *)out.data()); + + VT dr2 = A.transpose() * out; + VT dx1 = Hinv.cwiseProduct(dr1); + VT dx2 = Hinv.cwiseProduct(rx - dr2); + + // compute the step size + VT dx = dx1 + dx2; + NT tGrad = std::min(f.barrier.step_size(x, dx), 1.0); + dx = dx1 + tGrad * dx2; + NT tConst = std::min(0.99 * f.barrier.step_size(x, dx), 1.0); + tGrad = tGrad * tConst; + + // make the step + x = x + tConst * dx; + lambda = lambda - dr2; + + if (!f.barrier.feasible(x)) + { + break; + } + //If we have have converged + if (tGrad == 1) + { + //do some more fullStep + fullStep = fullStep + 1; + if (fullStep > log(dualErr / options.ipmDualTol) && fullStep > options.min_convergence_steps) + { + break; + } + } + else + { + fullStep = 0; + } + } + SpMat C; + VT d; + if (idx.size() == 0) + { + VT dist = f.barrier.boundary_distance(x); + NT th = options.ipmDistanceTol; + visit_lambda(dist, [&idx, th](double v, int i, int j) + { + if (v < th) + idx.push_back(i); }); + } + + if (idx.size() > 0) + { + C.resize(idx.size(), n); + std::pair pboundary = f.barrier.boundary(x); + VT A_ = pboundary.first; + VT b_ = pboundary.second; + A_ = A_(idx); + std::vector sparseIdx; + for (int i = 0; i < idx.size(); i++) + { + sparseIdx.push_back(Triple(i, i, A_(i))); + } + C.setFromTriplets(sparseIdx.begin(), sparseIdx.end()); + d = b_(idx); + } + else + { + C = MT::Zero(0, n).sparseView(); + d = VT::Zero(0, 1); + } + return std::make_tuple(x, C, d); +} +#endif diff --git a/include/preprocess/crhmc/crhmc_input.h b/include/preprocess/crhmc/crhmc_input.h new file mode 100644 index 000000000..984bd339f --- /dev/null +++ b/include/preprocess/crhmc/crhmc_input.h @@ -0,0 +1,111 @@ +// VolEsti (volume computation and sampling library) + +// Copyright (c) 2012-2020 Vissarion Fisikopoulos +// Copyright (c) 2018-2020 Apostolos Chalkis +// Copyright (c) 2022-2022 Ioannis Iakovidis + +// Contributed and/or modified by Ioannis Iakovidis, as part of Google Summer of +// Code 2022 program. + +// Licensed under GNU LGPL.3, see LICENCE file + +// References +// Yunbum Kook, Yin Tat Lee, Ruoqi Shen, Santosh S. Vempala. "Sampling with +// Riemannian Hamiltonian +// Monte Carlo in a Constrained Space" +#ifndef CRHMC_INPUT_H +#define CRHMC_INPUT_H +#include "Eigen/Eigen" +#include "opts.h" +/*0 funciton handles are given as a reference in case the user gives no +function. Then the uniform function is implied*/ +template +struct ZeroFunctor +{ + Point operator()(Point const &x) const { return Point(x.dimension()); } +}; +template +struct ZeroScalarFunctor +{ + using Type = typename Point::FT; + Type operator()(Point const &x) const { return 0; } +}; +/*Input structure: With this the user can define a polytope sampling problem*/ +template , + typename grad = ZeroFunctor, + typename hess = ZeroFunctor> +class crhmc_input +{ + using Type = typename Point::FT; + using VT = Eigen::Matrix; + ZeroFunctor zerof; + ZeroScalarFunctor zerosf; + +public: + using Func = func; + using Grad = grad; + using Hess = hess; + MatrixType Aineq; // Matrix of coefficients for the inequality constraints + VT bineq; // Right hand side of the inequality constraints + MatrixType Aeq; // Matrix of coefficients for the equality constraints + VT beq; // Right hand side of the equality constraints + opts options; // structure of the parameters of the problem + VT lb; // lb on the output coordinates preset to -1e7 + VT ub; // ub on the output coordinates preset to +1e7 + func &f; // Negative log density function handle + grad &df; // Negative log density gradient function handle + hess &ddf; // Negative log density hessian function handle + bool fZero; // whether f is completely zero + bool fHandle; // whether f is handle or not + bool dfHandle; // whether df is handle or not + bool ddfHandle; // whether ddf is handle or not + const Type inf = options.max_coord + 1; // helper for barrier handling + /*Constructors for different input instances*/ + crhmc_input(int dimension, func &function, grad &g, hess &h) + : f(function), df(g), ddf(h) + { + fZero = false; + fHandle = true; + dfHandle = true; + ddfHandle = true; + init(dimension); + } + crhmc_input(int dimension, func &function) + : f(function), df(zerof), ddf(zerof) + { + fZero = false; + fHandle = true; + dfHandle = false; + ddfHandle = false; + init(dimension); + } + crhmc_input(int dimension, func &function, grad &g) + : f(function), df(g), ddf(zerof) + { + fZero = false; + fHandle = true; + dfHandle = true; + ddfHandle = false; + init(dimension); + } + crhmc_input(int dimension) : f(zerosf), df(zerof), ddf(zerof) + { + fZero = true; + fHandle = false; + dfHandle = false; + ddfHandle = false; + init(dimension); + } + + void init(int dimension) + { + Aineq.resize(0, dimension); + Aeq.resize(0, dimension); + bineq.resize(0, 1); + beq.resize(0, 1); + lb = -VT::Ones(dimension) * inf; + ub = VT::Ones(dimension) * inf; + } +}; +#endif diff --git a/include/preprocess/crhmc/crhmc_problem.h b/include/preprocess/crhmc/crhmc_problem.h new file mode 100644 index 000000000..1374944ff --- /dev/null +++ b/include/preprocess/crhmc/crhmc_problem.h @@ -0,0 +1,659 @@ +// VolEsti (volume computation and sampling library) + +// Copyright (c) 2012-2020 Vissarion Fisikopoulos +// Copyright (c) 2018-2020 Apostolos Chalkis +// Copyright (c) 2022-2022 Ioannis Iakovidis + +// Contributed and/or modified by Ioannis Iakovidis, as part of Google Summer of +// Code 2022 program. + +// Licensed under GNU LGPL.3, see LICENCE file + +// References +// Yunbum Kook, Yin Tat Lee, Ruoqi Shen, Santosh S. Vempala. "Sampling with +// Riemannian Hamiltonian +// Monte Carlo in a Constrained Space" +#ifndef CRHMC_PROBLEM_H +#define CRHMC_PROBLEM_H +#include "Eigen/Eigen" +#include "PackedCSparse/PackedChol.h" +#include "cartesian_geom/cartesian_kernel.h" +#include "convex_bodies/hpolytope.h" +#include "preprocess/crhmc/analytic_center.h" +#include "preprocess/crhmc/crhmc_input.h" +#include "preprocess/crhmc/crhmc_utils.h" +#include "preprocess/crhmc/lewis_center.h" +#include "preprocess/crhmc/opts.h" +#include "sos/barriers/TwoSidedBarrier.h" +#include +#include +#include +#include +#include + +#ifndef SIMD_LEN +#define SIMD_LEN 0 +#endif +const size_t chol_k = (SIMD_LEN == 0) ? 1 : SIMD_LEN; +template +class crhmc_problem { +public: + using NT = double; + using PolytopeType = HPolytope; + using MT = Eigen::Matrix; + using VT = Eigen::Matrix; + using IVT = Eigen::Matrix; + using SpMat = Eigen::SparseMatrix; + using PM = Eigen::PermutationMatrix; + using IndexVector = Eigen::Matrix; + using CholObj = PackedChol; + using Triple = Eigen::Triplet; + using Barrier = TwoSidedBarrier; + using Tx = FloatArray; + using Opts = opts; + using Diagonal_MT = Eigen::DiagonalMatrix; + using Func = typename Input::Func; + using Grad = typename Input::Grad; + using Hess = typename Input::Hess; + + unsigned int _d; // dimension + // Problem variables Ax=b st lb<=x<=ub + MT A; // matrix A input matrix + SpMat Asp; // problem matrix A in Sparse form + VT b; // vector b, s.t.: Ax=b + VT lb; // Lower bound for output coordinates + VT ub; // Upper bound for output coordinates + Barrier barrier; // Class that holds functions that handle the log barrier for + // lb and ub + Opts options; // problem parameters + // Transformation (T,y) such that the new variables x + // can be tranform to the original z (z= Tx+y) + SpMat T; + VT y; + // Non zero indices and values for fast tranform + std::vector Tidx; // T x = x(Tidx) .* Ta + VT Ta; // T x = x(Tidx) .* Ta + bool isempty_center = true; + VT center = VT::Zero(0, 1); // Resulting polytope Lewis or Analytic center + VT analytic_ctr; //analytic center vector (for testing) + VT w_center;// weights of the lewis center + + VT width; // width of the varibles + int nP;//input dimension + + Func &func; // function handle + Grad &df; // gradient handle + Hess &ddf; // hessian handle + bool fZero; // whether f is completely zero + bool fHandle; // whether f is handle or not + bool dfHandle; // whether df is handle or not + bool ddfHandle; // whether ddf is handle or not +#ifdef TIME_KEEPING +//Timing information + std::chrono::duration rescale_duration, sparsify_duration, + reordering_duration, rm_rows_duration, rm_fixed_vars_duration, + ex_collapsed_vars_duration, shift_barrier_duration, lewis_center_duration; +#endif + const NT inf = options.max_coord + 1; // helper for barrier handling + int equations() const { return Asp.rows(); } + int dimension() const { return Asp.cols(); } + + // Remove varibles that have width under some tolerance + int remove_fixed_variables(const NT tol = 1e-12) { + int m = Asp.rows(); + int n = Asp.cols(); + VT d = estimate_width(); + CholObj solver = CholObj(transform_format(Asp)); + VT w = VT::Ones(n, 1); + solver.decompose((Tx *)w.data()); + VT out_vector = VT(m, 1); + solver.solve((Tx *)b.data(), (Tx *)out_vector.data()); + VT x = Asp.transpose() * out_vector; + + x = ((x.array()).abs() < tol).select(0., x); + std::vector freeIndices; + std::vector indices; + int nFreeVars = 0; + for (int i = 0; i < n; i++) { + if (d(i) < tol * (1 + abs(x(i)))) { + } else { + freeIndices.push_back(Triple(i, nFreeVars, 1)); + nFreeVars++; + indices.push_back(i); + x(i) = 0.0; + } + } + + if (freeIndices.size() != n) { + SpMat S = SpMat(n, freeIndices.size()); + S.setFromTriplets(freeIndices.begin(), freeIndices.end()); + append_map(S, x); + barrier.set_bound(barrier.lb(indices), barrier.ub(indices)); + return 1; + } + return 0; + } + + int extract_collapsed_variables() { + SpMat Ac; + VT bc; + if (isempty_center) { + std::tie(center, Ac, bc) = analytic_center(Asp, b, *this, options); + isempty_center = false; + } else { + std::tie(center, Ac, bc) = + analytic_center(Asp, b, *this, options, center); + analytic_ctr=center; + } + if (Ac.rows() == 0) { + return 0; + } + SpMat _A = Asp; + sparse_stack_v(Ac, _A, Asp); + b.resize(b.rows() + bc.rows(), 1); + b << bc, b; + return 1; + } + // Rescale the polytope for numerical stability + void rescale(const VT x = VT::Zero(0, 1)) { + if (std::min(equations(), dimension()) <= 1) { + return; + } + VT hess; + if (x.rows() == 0) { + hess = VT::Ones(dimension(), 1); + } else { + std::tie(std::ignore, hess) = analytic_center_oracle(x); + hess = hess + (width.cwiseProduct(width)).cwiseInverse(); + } + VT scale = (hess.cwiseSqrt()).cwiseInverse(); + SpMat Ain = Asp * scale.asDiagonal(); + VT cscale; + VT rscale; + + std::tie(cscale, rscale) = gmscale(Ain, 0.9); + Asp = (rscale.cwiseInverse()).asDiagonal() * Asp; + b = b.cwiseQuotient(rscale); + barrier.set_bound(barrier.lb.cwiseProduct(cscale), + barrier.ub.cwiseProduct(cscale)); + append_map((cscale.cwiseInverse()).asDiagonal(), VT::Zero(dimension(), 1)); + if (!isempty_center) { + center = center.cwiseProduct(cscale); + } + } + + // Rewrite P so that each cols has no more than maxNZ non-zeros + void splitDenseCols(const int maxnz) { + int m = Asp.rows(); + int n = Asp.cols(); + if (m <= maxnz) { + return; + } + if (Asp.nonZeros() > maxnz * n) { + return; + } + int numBadCols = 1; + lb = barrier.lb; + ub = barrier.ub; + //until there are columns with more than maxNZ elements + while (numBadCols > 0) { + m = Asp.rows(); + n = Asp.cols(); + std::vector colCounts(n); + std::vector badCols; + numBadCols = 0; + //find the columns with count larger than maxNZ + std::tie(colCounts, badCols) = nnzPerColumn(Asp, maxnz); + numBadCols = badCols.size(); + if (numBadCols == 0) { + break; + } + //create a new variable for each one and update Asp, b, lb, ub, T, y accordingly + SpMat A_; + SpMat Aj(m, numBadCols); + SpMat Ai(numBadCols, n + numBadCols); + std::vector newColumns; + std::vector newRows; + b.conservativeResize(m + numBadCols, 1); + lb.conservativeResize(n + numBadCols, 1); + ub.conservativeResize(n + numBadCols, 1); + + for (int j = 0; j < numBadCols; j++) { + int i = badCols[j]; + int k = 0; + for (SpMat::InnerIterator it(Asp, i); it; ++it) { + if (k >= colCounts[i] / 2) { + newColumns.push_back(Triple(it.row(), j, it.value())); + it.valueRef() = 0; + } + k++; + } + newRows.push_back(Triple(j, i, 1)); + newRows.push_back(Triple(j, j + n, -1)); + lb(n + j) = lb(i); + ub(n + j) = ub(i); + b(m + j) = 0; + } + Ai.setFromTriplets(newRows.begin(), newRows.end()); + Aj.setFromTriplets(newColumns.begin(), newColumns.end()); + Asp.prune(0, 0); + sparse_stack_h_inplace(Asp, Aj); + sparse_stack_v(Asp, Ai, A_); + Asp = A_; + } + SpMat _T = MT::Zero(T.rows(), ub.rows() - T.cols()).sparseView(); + sparse_stack_h_inplace(T, _T); + updateT(); + barrier.set_bound(lb, ub); + } + // Change A and the correpsonding Transformation + template + void append_map(MatrixType const &S, VT const &z) { + b = b - Asp * z; + Asp = Asp * S; + y = y + T * z; + T = T * S; + updateT(); + } + // Shift the problem with respect to x + void shift_barrier(VT const &x) { + int size = x.rows(); + b = b - Asp * x; + y = y + T * x; + barrier.set_bound(barrier.lb - x, barrier.ub - x); + if (!isempty_center) { + center = center - x; + } + } + // Reorder the polytope accordint to the AMD Reordering for better sparsity + // pattern in the Cholesky decomposition + void reorder() { + if (!options.EnableReordering) { + return; + } + Asp.prune(0.0); + Asp.makeCompressed(); + int m = Asp.rows(); + SpMat H; + H = Asp * SpMat(Asp.transpose()) + MT::Identity(m, m); + H.makeCompressed(); + PM permed = permuteMatAMD(H); + H = permed * H * permed.transpose(); + PM post_perm = postOrderPerm(H); + PM perm = permed * post_perm; + Asp = perm * Asp; + b = perm * b; + } +//Using the Cholesky decomposition remove dependent rows in the systen Asp*x=b + int remove_dependent_rows(NT tolerance = 1e-12, NT infinity = 1e+64) { + //this approach does not work with 0 collumns + remove_zero_rows(Asp); + int m = Asp.rows(); + int n = Asp.cols(); + VT v = VT(m); + VT w = VT::Ones(n, 1); + CholObj solver = CholObj(transform_format(Asp)); + solver.decompose((Tx *)w.data()); + solver.diagL((Tx *)v.data()); + std::vector indices; + for (int i = 0; i < m; i++) { + if ((v(i) > tolerance) && (v(i) < infinity)) { + indices.push_back(i); + } + } + if (indices.size() == m) { + return 0; + } + + Asp = A(indices, Eigen::all).sparseView(); + b = b(indices); + return 1; + } +//Apply number of operations that simplify the problem + void simplify() { +#ifdef TIME_KEEPING + std::chrono::time_point start, end; + start = std::chrono::system_clock::now(); +#endif + rescale(); +#ifdef TIME_KEEPING + end = std::chrono::system_clock::now(); + rescale_duration += end - start; + start = std::chrono::system_clock::now(); +#endif + splitDenseCols(options.maxNZ); +#ifdef TIME_KEEPING + end = std::chrono::system_clock::now(); + sparsify_duration += end - start; + start = std::chrono::system_clock::now(); +#endif + reorder(); +#ifdef TIME_KEEPING + end = std::chrono::system_clock::now(); + reordering_duration += end - start; +#endif + int changed = 1; + while (changed) { + while (changed) { + changed = 0; +#ifdef TIME_KEEPING + start = std::chrono::system_clock::now(); +#endif + changed += remove_dependent_rows(); +#ifdef TIME_KEEPING + end = std::chrono::system_clock::now(); + rm_rows_duration += end - start; + start = std::chrono::system_clock::now(); +#endif + changed += remove_fixed_variables(); +#ifdef TIME_KEEPING + end = std::chrono::system_clock::now(); + rm_fixed_vars_duration += end - start; + start = std::chrono::system_clock::now(); +#endif + reorder(); +#ifdef TIME_KEEPING + end = std::chrono::system_clock::now(); + reordering_duration += end - start; +#endif + } +#ifdef TIME_KEEPING + start = std::chrono::system_clock::now(); +#endif + changed += extract_collapsed_variables(); +#ifdef TIME_KEEPING + end = std::chrono::system_clock::now(); + ex_collapsed_vars_duration += end - start; +#endif + } + } + + VT estimate_width() { + int n = Asp.cols(); + VT hess = VT::Ones(n, 1); + CholObj solver = CholObj(transform_format(Asp)); + solver.decompose((Tx *)hess.data()); + VT w_vector(n, 1); + solver.leverageScoreComplement((Tx *)w_vector.data()); + w_vector = (w_vector.cwiseMax(0)).cwiseProduct(hess.cwiseInverse()); + VT tau = w_vector.cwiseSqrt(); + + return tau; + } + + void print(std::string const message = "Printing Sparse problem") { + std::cerr << "----------------" << message << "--------------" << '\n'; + std::cerr << "(m,n) = " << equations() << " , " << dimension() + << " nnz= " << Asp.nonZeros() << "\n"; + if (equations() > 20 || dimension() > 20) { + std::cerr << "too big for complete visulization\n"; + return; + } + std::cerr << "A=\n"; + + std::cerr << MT(Asp); + std::cerr << "\n"; + + std::cerr << "b=\n"; + std::cerr << b; + std::cerr << "\n"; + + std::cerr << "lb=\n"; + std::cerr << barrier.lb; + std::cerr << "\n"; + + std::cerr << "ub=\n"; + std::cerr << barrier.ub; + std::cerr << "\n"; + + std::cerr << "T=\n"; + std::cerr << MT(T); + std::cerr << "\n"; + + std::cerr << "y=\n"; + std::cerr << y; + std::cerr << "\n"; + + std::cerr << "center=\n"; + std::cerr << center; + std::cerr << "\n"; + } + + void print(const char *fileName) { + std::ofstream myfile; + myfile.open(fileName); + myfile << Asp.rows() << " " << Asp.cols() << "\n"; + + myfile << MT(Asp); + myfile << "\n"; + myfile << "\n"; + + myfile << b; + myfile << "\n"; + myfile << "\n"; + + myfile << barrier.lb; + myfile << "\n"; + myfile << "\n"; + + myfile << barrier.ub; + myfile << "\n"; + myfile << "\n"; + + myfile << MT(T); + myfile << "\n"; + myfile << "\n"; + + myfile << y; + myfile << "\n"; + myfile << "\n"; + + myfile << center; + } +//Class constructor + crhmc_problem(Input const &input, Opts _options = Opts()) + : options(_options), func(input.f), df(input.df), ddf(input.ddf), + fZero(input.fZero), fHandle(input.fHandle), dfHandle(input.dfHandle), + ddfHandle(input.ddfHandle) { +#ifdef TIME_KEEPING + rescale_duration = sparsify_duration = reordering_duration = + rm_rows_duration = rm_fixed_vars_duration = ex_collapsed_vars_duration = + shift_barrier_duration = lewis_center_duration = + std::chrono::duration::zero(); +#endif + + nP = input.Aeq.cols(); + int nIneq = input.Aineq.rows(); + int nEq = input.Aeq.rows(); + A.resize(nEq + nIneq, nP + nIneq); + A << input.Aeq, MT::Zero(nEq, nIneq), input.Aineq, + MT::Identity(nIneq, nIneq); + b.resize(nEq + nIneq, 1); + b << input.beq, input.bineq; + lb.resize(nP + nIneq, 1); + ub.resize(nP + nIneq, 1); + lb << input.lb, MT::Zero(nIneq, 1); + ub << input.ub, MT::Ones(nIneq, 1) * inf; + Asp.resize(nEq + nIneq, nP + nIneq); + PreproccessProblem(); + } + // Initialization funciton + void PreproccessProblem() { + int n = dimension(); + /*Move lb=ub to Ax=b*/ + for (int i = 0; i < n; i++) { + if (doubleVectorEqualityComparison(lb(i), ub(i))) { + MT temp = MT::Zero(1, n); + temp(i) = 1; + A.conservativeResize(A.rows() + 1, A.cols()); + A.row(A.rows() - 1) = temp; + b.conservativeResize(b.rows() + 1); + b(b.rows() - 1) = (lb(i) + ub(i)) / 2; + lb(i) = -inf; + ub(i) = inf; + } + } + + barrier.set_bound(lb.cwiseMax(-1e7), ub.cwiseMin(1e7)); + + Asp = A.sparseView(); + NT tol = std::numeric_limits::epsilon(); + Asp.prune(tol, tol); + /*Update the transformation Tx + y*/ + T = SpMat(nP, n); + std::vector indices; + for (int i = 0; i < nP; i++) { + indices.push_back(Triple(i, i, 1)); + } + T.setFromTriplets(indices.begin(), indices.end()); + Tidx = std::vector(T.rows()); + updateT(); + y = VT::Zero(nP, 1); + /*Simplify*/ + if (!fZero) { + fZero = true; + simplify(); + fZero = false; + } + simplify(); +#ifdef TIME_KEEPING + std::chrono::time_point start, end; + start = std::chrono::system_clock::now(); +#endif + if (isempty_center) { + std::tie(center, std::ignore, std::ignore) = + analytic_center(Asp, b, *this, options); + isempty_center = false; + } + shift_barrier(center); +#ifdef TIME_KEEPING + end = std::chrono::system_clock::now(); + shift_barrier_duration += end - start; +#endif + reorder(); + + width = estimate_width(); + if (width.maxCoeff() > 1e9) { + std::cerr << "Domain seems to be unbounded. Either add a Gaussian term " + "via f, df, ddf or add bounds to variable via lb and ub." + << '\n'; + exit(1); + } + // Recenter again and make sure it is feasible + VT hess; +#ifdef TIME_KEEPING + start = std::chrono::system_clock::now(); +#endif + std::tie(center, std::ignore, std::ignore, w_center) = + lewis_center(Asp, b, *this, options, center); + std::tie(std::ignore, hess) = lewis_center_oracle(center, w_center); + CholObj solver = CholObj(transform_format(Asp)); + VT Hinv = hess.cwiseInverse(); + solver.decompose((Tx *)Hinv.data()); + VT out(equations(), 1); + VT input = (b - Asp * center); + solver.solve((Tx *)input.data(), (Tx *)out.data()); + center = center + (Asp.transpose() * out).cwiseProduct(Hinv); +#ifdef TIME_KEEPING + end = std::chrono::system_clock::now(); + lewis_center_duration += end - start; +#endif + if ((center.array() > barrier.ub.array()).any() || + (center.array() < barrier.lb.array()).any()) { + std::cerr << "Polytope:Infeasible. The algorithm cannot find a feasible " + "point.\n"; + exit(1); + } +#ifdef TIME_KEEPING + std::cerr << "Rescale completed in time, "; + std::cerr << rescale_duration.count() << " secs " << std::endl; + std::cerr << "Split dense columns completed in time, "; + std::cerr << sparsify_duration.count() << " secs " << std::endl; + std::cerr << "Reordering completed in time, "; + std::cerr << reordering_duration.count() << " secs " << std::endl; + std::cerr << "Removing dependent rows completed in time, "; + std::cerr << rm_rows_duration.count() << " secs " << std::endl; + std::cerr << "Removing fixed variables completed in time, "; + std::cerr << rm_fixed_vars_duration.count() << " secs " << std::endl; + std::cerr << "Extracting collapsed variables completed in time, "; + std::cerr << ex_collapsed_vars_duration.count() << " secs " << std::endl; + std::cerr << "Shift_barrier completed in time, "; + std::cerr << shift_barrier_duration.count() << " secs " << std::endl; + std::cerr << "Finding Center completed in time, "; + std::cerr << lewis_center_duration.count() << " secs " << std::endl; +#endif + } + + // Gradient and hessian of for the analytic center + std::pair analytic_center_oracle(VT const &x) { + VT g, h; + std::tie(std::ignore, g, h) = f_oracle(x); + return std::make_pair(g + barrier.gradient(x), h + barrier.hessian(x)); + } + // Gradient and hessian of for the lewis center + std::pair lewis_center_oracle(VT const &x, VT const &w) { + VT g, h; + std::tie(std::ignore, g, h) = f_oracle(x); + return std::make_pair(g + w.cwiseProduct(barrier.gradient(x)), + h + w.cwiseProduct(barrier.hessian(x))); + } + // Function that uses the transformation (T,y) to apply the function to the + // original variables + std::tuple f_oracle(VT x) { + NT f; + VT g, h; + int n = x.rows(); + if (fZero) { + f = 0; + g = VT::Zero(n); + h = VT::Zero(n); + return std::make_tuple(f, g, h); + } + // Take the correpsonding point in the original space + VT z = VT::Zero(n); + if (fHandle || dfHandle || ddfHandle) { + z(Tidx, Eigen::all) = Ta.cwiseProduct(x(Tidx, Eigen::all)) + y; + } + + // If the function is given evaluate it at the original point + if (fHandle) { + f = func(Point(z)); + } else { + f = 0; + } + // If the gradient is given evaluate it at the original point + if (dfHandle) { + g = VT::Zero(n, 1); + g(Tidx, Eigen::all) = Ta.cwiseProduct(df(Point(z)).getCoefficients()); + } else { + g = VT::Zero(n, 1); + } + // If the hessian is given evaluate it at the original point + if (ddfHandle) { + h = VT::Zero(n, 1); + h(Tidx, Eigen::all) = + (Ta.cwiseProduct(Ta)).cwiseProduct(ddf(Point(z)).getCoefficients()); + } else { + h = VT::Zero(n, 1); + } + return std::make_tuple(f, -g, h); + } + + // Update the indices and values vectors of the matrix T + void updateT() { + int n = T.cols(); + int m = T.rows(); + Ta = VT(m); + // By construction each row of T has ar most one nonZero + for (int k = 0; k < T.outerSize(); ++k) { + for (SpMat::InnerIterator it(T, k); it; ++it) { + int pos = (int)it.row(); + int nz = it.col(); + Tidx[pos] = nz; + } + } + + Ta = T * VT::Ones(n, 1); + } +}; +#endif diff --git a/include/preprocess/crhmc/crhmc_utils.h b/include/preprocess/crhmc/crhmc_utils.h new file mode 100644 index 000000000..cfb116a68 --- /dev/null +++ b/include/preprocess/crhmc/crhmc_utils.h @@ -0,0 +1,371 @@ +// VolEsti (volume computation and sampling library) + +// Copyright (c) 2012-2020 Vissarion Fisikopoulos +// Copyright (c) 2018-2020 Apostolos Chalkis +// Copyright (c) 2022-2022 Ioannis Iakovidis + +// Contributed and/or modified by Ioannis Iakovidis, as part of Google Summer of +// Code 2022 program. + +// Licensed under GNU LGPL.3, see LICENCE file +#ifndef CRHMC_UTILS_H +#define CRHMC_UTILS_H +#include "Eigen/Eigen" +#include "PackedCSparse/SparseMatrix.h" +#include +#include + +template +struct lambda_as_visitor_wrapper : Func +{ + lambda_as_visitor_wrapper(const Func &f) : Func(f) {} + template + void init(const S &v, I i, I j) + { + return Func::operator()(v, i, j); + } +}; + +template +void visit_lambda(const Mat &m, const Func &f) +{ + lambda_as_visitor_wrapper visitor(f); + m.visit(visitor); +} + +template +void sparse_stack_v(const SparseMatrixType &top, const SparseMatrixType &bottom, + SparseMatrixType &stacked) +{ + assert(top.cols() == bottom.cols()); + stacked.resize(top.rows() + bottom.rows(), top.cols()); + stacked.resizeNonZeros(top.nonZeros() + bottom.nonZeros()); + + int i = 0; + + for (int col = 0; col < top.cols(); col++) + { + stacked.outerIndexPtr()[col] = i; + + for (int j = top.outerIndexPtr()[col]; j < top.outerIndexPtr()[col + 1]; + j++, i++) + { + stacked.innerIndexPtr()[i] = top.innerIndexPtr()[j]; + stacked.valuePtr()[i] = top.valuePtr()[j]; + } + + for (int j = bottom.outerIndexPtr()[col]; + j < bottom.outerIndexPtr()[col + 1]; j++, i++) + { + stacked.innerIndexPtr()[i] = (int)top.rows() + bottom.innerIndexPtr()[j]; + stacked.valuePtr()[i] = bottom.valuePtr()[j]; + } + } + stacked.outerIndexPtr()[top.cols()] = i; +} + +template +void sparse_stack_h(const SparseMatrixType &left, const SparseMatrixType &right, + SparseMatrixType &stacked) +{ + assert(left.rows() == right.rows()); + + stacked.resize(left.rows(), left.cols() + right.cols()); + stacked.resizeNonZeros(left.nonZeros() + right.nonZeros()); + + std::copy(left.innerIndexPtr(), left.innerIndexPtr() + left.nonZeros(), + stacked.innerIndexPtr()); + std::copy(right.innerIndexPtr(), right.innerIndexPtr() + right.nonZeros(), + stacked.innerIndexPtr() + left.nonZeros()); + + std::copy(left.valuePtr(), left.valuePtr() + left.nonZeros(), + stacked.valuePtr()); + std::copy(right.valuePtr(), right.valuePtr() + right.nonZeros(), + stacked.valuePtr() + left.nonZeros()); + + std::copy(left.outerIndexPtr(), left.outerIndexPtr() + left.cols(), + stacked.outerIndexPtr()); // dont need the last entry of + // A.outerIndexPtr() -- total length is + // AB.cols() + 1 = A.cols() + B.cols() + 1 + std::transform(right.outerIndexPtr(), + right.outerIndexPtr() + right.cols() + 1, + stacked.outerIndexPtr() + left.cols(), + [&](int i) + { return i + left.nonZeros(); }); +} + +template +void sparse_stack_h_inplace(SparseMatrixType &left, + const SparseMatrixType &right) +{ + assert(left.rows() == right.rows()); + + const int leftcol = (int)left.cols(); + const int leftnz = (int)left.nonZeros(); + + left.conservativeResize(left.rows(), left.cols() + right.cols()); + left.resizeNonZeros(left.nonZeros() + right.nonZeros()); + + std::copy(right.innerIndexPtr(), right.innerIndexPtr() + right.nonZeros(), + left.innerIndexPtr() + leftnz); + std::copy(right.valuePtr(), right.valuePtr() + right.nonZeros(), + left.valuePtr() + leftnz); + std::transform( + right.outerIndexPtr(), right.outerIndexPtr() + right.cols() + 1, + left.outerIndexPtr() + leftcol, [&](int i) + { return i + leftnz; }); +} + +template +void remove_zero_rows(SparseMatrixType &A) +{ + std::vector> tripletList; + unsigned Ndata = A.cols(); + unsigned Nbins = A.rows(); + for (int k = 0; k < A.outerSize(); ++k) + { + for (typename SparseMatrixType::InnerIterator it(A, k); it; ++it) + { + tripletList.push_back( + Eigen::Triplet(it.row(), it.col(), it.value())); + } + } + // get which rows are empty + std::vector has_value(Nbins, false); + for (auto tr : tripletList) + has_value[tr.row()] = true; + + if (std::all_of(has_value.begin(), has_value.end(), + [](bool v) + { return v; })) + { + return; + } + // create map from old to new indices + std::map row_map; + unsigned new_idx = 0; + for (unsigned old_idx = 0; old_idx < Nbins; old_idx++) + if (has_value[old_idx]) + row_map[old_idx] = new_idx++; + + // make new triplet list, dropping empty rows + std::vector> newTripletList; + newTripletList.reserve(Ndata); + for (auto tr : tripletList) + newTripletList.push_back( + Eigen::Triplet(row_map[tr.row()], tr.col(), tr.value())); + + // form new matrix and return + SparseMatrixType ret(new_idx, Ndata); + ret.setFromTriplets(newTripletList.begin(), newTripletList.end()); + A = SparseMatrixType(ret); +} + +template +void remove_rows(SparseMatrixType &A, std::vector indices) +{ + std::vector> tripletList; + unsigned Ndata = A.cols(); + unsigned Nbins = A.rows(); + for (int k = 0; k < A.outerSize(); ++k) + { + for (typename SparseMatrixType::InnerIterator it(A, k); it; ++it) + { + tripletList.push_back( + Eigen::Triplet(it.row(), it.col(), it.value())); + } + } + + std::vector notRemoved(Nbins, false); + for (auto tr : indices) + notRemoved[tr] = true; + + if (std::all_of(notRemoved.begin(), notRemoved.end(), + [](bool v) + { return v; })) + { + return; + } + // create map from old to new indices + std::map row_map; + unsigned new_idx = 0; + for (unsigned old_idx = 0; old_idx < Nbins; old_idx++) + if (notRemoved[old_idx]) + row_map[old_idx] = new_idx++; + + // make new triplet list, dropping empty rows + std::vector> newTripletList; + newTripletList.reserve(Ndata); + for (auto tr : tripletList) + newTripletList.push_back( + Eigen::Triplet(row_map[tr.row()], tr.col(), tr.value())); + + // form new matrix and return + SparseMatrixType ret(new_idx, Ndata); + ret.setFromTriplets(newTripletList.begin(), newTripletList.end()); + A = SparseMatrixType(ret); +} + +template +std::pair colwiseMinMax(SparseMatrixType const &A) +{ + int n = A.cols(); + VectorType cmax(n); + VectorType cmin(n); + for (int k = 0; k < A.outerSize(); ++k) + { + Type minv = +std::numeric_limits::max(); + Type maxv = std::numeric_limits::lowest(); + for (typename SparseMatrixType::InnerIterator it(A, k); it; ++it) + { + minv = std::min(minv, it.value()); + maxv = std::max(maxv, it.value()); + } + cmin(k) = minv; + cmax(k) = maxv; + } + return std::make_pair(cmin, cmax); +} +template +void nextpow2(VectorType &a) +{ + a = (a.array() == 0).select(1, a); + a = (((a.array().log()) / std::log(2)).ceil()).matrix(); + a = pow(2, a.array()).matrix(); +} +template +std::pair gmscale(SparseMatrixType &Asp, + const Type scltol) +{ + using Diagonal_MT = Eigen::DiagonalMatrix; + int m = Asp.rows(); + int n = Asp.cols(); + SparseMatrixType A = Asp.cwiseAbs(); + A.makeCompressed(); + int maxpass = 10; + Type aratio = 1e+50; + Type sratio; + Type damp = 1e-4; + Type small = 1e-8; + VectorType rscale = VectorType ::Ones(m, 1); + VectorType cscale = VectorType ::Ones(n, 1); + VectorType cmax; + VectorType cmin; + VectorType rmax; + VectorType rmin; + VectorType eps = VectorType ::Ones(n, 1) * 1e-12; + SparseMatrixType SA; + for (int npass = 0; npass < maxpass; npass++) + { + + rscale = (rscale.array() == 0).select(1, rscale); + Diagonal_MT Rinv = (rscale.cwiseInverse()).asDiagonal(); + SA = Rinv * A; + std::tie(cmin, cmax) = + colwiseMinMax(SA); + + // cmin = (cmin + eps).cwiseInverse(); + sratio = (cmax.cwiseQuotient(cmin)).maxCoeff(); + + if (npass > 0) + { + cscale = ((cmin.cwiseMax(damp * cmax)).cwiseProduct(cmax)).cwiseSqrt(); + } + + if (npass >= 2 && sratio >= aratio * scltol) + { + break; + } + aratio = sratio; + nextpow2(cscale); + Diagonal_MT Cinv = (cscale.cwiseInverse()).asDiagonal(); + SA = A * Cinv; + std::tie(rmin, rmax) = + colwiseMinMax(SA.transpose()); + // rmin = (rmin + eps).cwiseInverse(); + rscale = ((rmin.cwiseMax(damp * rmax)).cwiseProduct(rmax)).cwiseSqrt(); + nextpow2(rscale); + } + rscale = (rscale.array() == 0).select(1, rscale); + Diagonal_MT Rinv = (rscale.cwiseInverse()).asDiagonal(); + SA = Rinv * A; + std::tie(std::ignore, cscale) = + colwiseMinMax(SA); + nextpow2(cscale); + return std::make_pair(cscale, rscale); +} +template +int doubleVectorEqualityComparison( + const Type a, const Type b, + const Type tol = std::numeric_limits::epsilon()) +{ + return (abs(a - b) < tol * (1 + abs(a) + abs(b))); +} + +template +std::pair, std::vector> +nnzPerColumn(SparseMatrixType const &A, const int threashold) +{ + int n = A.cols(); + std::vector colCounts(n); + std::vector badCols; + for (int k = 0; k < A.outerSize(); ++k) + { + int nnz = 0; + for (typename SparseMatrixType::InnerIterator it(A, k); it; ++it) + { + if (it.value() != 0) + { + nnz++; + } + } + colCounts[k] = nnz; + if (nnz > threashold) + { + badCols.push_back(k); + } + } + return std::make_pair(colCounts, badCols); +} +using PM = Eigen::PermutationMatrix; +template +PM permuteMatAMD(SparseMatrixType const &A) +{ + Eigen::AMDOrdering ordering; + PM perm; + ordering(A, perm); + return perm; +} +template +PM postOrderPerm(SparseMatrixType const &A) +{ + using IndexVector = Eigen::Matrix; + int n = A.rows(); + IndexVector m_etree; + IndexVector firstRowElt; + Eigen::internal::coletree(A, m_etree, firstRowElt); + IndexVector post; + Eigen::internal::treePostorder(int(A.cols()), m_etree, post); + PM post_perm(n); + for (int i = 0; i < n; i++) + post_perm.indices()(i) = post(i); + return post_perm; +} + +template +PackedCSparse::SparseMatrix transform_format(SparseMatrixType const &mat) { + PackedCSparse::SparseMatrix A = PackedCSparse::SparseMatrix(mat.rows(), mat.cols(), mat.nonZeros()); + IndexType nnz = 0; + for (IndexType outeindex = 0; outeindex < mat.outerSize(); ++outeindex) { + A.p[outeindex] = nnz; + for (typename SparseMatrixType::InnerIterator it(mat, outeindex); it; ++it) { + A.i[nnz] = it.row(); + A.x[nnz] = it.value(); + nnz++; + } + } + A.p[A.n] = nnz; + return A; +} + +#endif diff --git a/include/preprocess/crhmc/lewis_center.h b/include/preprocess/crhmc/lewis_center.h new file mode 100644 index 000000000..bae50d622 --- /dev/null +++ b/include/preprocess/crhmc/lewis_center.h @@ -0,0 +1,193 @@ +// VolEsti (volume computation and sampling library) + +// Copyright (c) 2012-2020 Vissarion Fisikopoulos +// Copyright (c) 2018-2020 Apostolos Chalkis +// Copyright (c) 2022-2022 Ioannis Iakovidis + +// Contributed and/or modified by Ioannis Iakovidis, as part of Google Summer of +// Code 2022 program. + +// Licensed under GNU LGPL.3, see LICENCE file + +// References +// Yunbum Kook, Yin Tat Lee, Ruoqi Shen, Santosh S. Vempala. "Sampling with +// Riemannian Hamiltonian +// Monte Carlo in a Constrained Space" +#ifndef LEWIS_CENTER_H +#define LEWIS_CENTER_H +#include "Eigen/Eigen" +#include "PackedCSparse/PackedChol.h" +#include "preprocess/crhmc/crhmc_utils.h" +#include "preprocess/crhmc/opts.h" +#include "sos/barriers/TwoSidedBarrier.h" +#include +#include +#include +#ifndef SIMD_LEN +#define SIMD_LEN 0 +#endif +const size_t chol_k3 = (SIMD_LEN == 0) ? 1 : SIMD_LEN; + +using NT = double; +using MT = Eigen::Matrix; +using VT = Eigen::Matrix; +using SpMat = Eigen::SparseMatrix; +using CholObj = PackedChol; +using Triple = Eigen::Triplet; +using Tx = FloatArray; +using Opts = opts; +NT epsilon = 1e-8; +/*This function computes the Lewis center of the polytope*/ +//And detects additional constraint that need to be added +// x - It outputs the minimizer of min f(x) subjects to {Ax=b} +// w - Output weights that correspond to the Lewis center, they are gone be used in the sampler to reduce the conditon number +// C - detected constraint matrix +// If the domain ({Ax=b} intersect dom(f)) is not full dimensional in {Ax=b} +// because of the dom(f), the algorithm will detect the collapsed dimension +// and output the detected constraint C x = d +// d - detected constraint vector +template +std::tuple lewis_center(SpMat const &A, VT const &b, Polytope &f, Opts const &options, VT x = VT::Zero(0, 1)) +{ + // initial conditions + int n = A.cols(); + int m = A.rows(); + //If it is given use starting point + if (x.rows() == 0 || !f.barrier.feasible(x)) + { + x = f.barrier.center; + } + VT lambda = VT::Zero(n, 1); + int fullStep = 0; + NT tConst = 0; + NT primalErr = std::numeric_limits::max(); + NT dualErr = std::numeric_limits::max(); + NT primalErrMin = std::numeric_limits::max(); + NT primalFactor = 1; + NT dualFactor = 1 + b.norm(); + std::vector idx; + + CholObj solver = CholObj(transform_format(A)); + VT w = VT::Ones(n, 1); + VT wp = w; + for (int iter = 0; iter < options.ipmMaxIter; iter++) + { + std::pair pair_analytic_oracle = f.lewis_center_oracle(x, wp); + VT grad = pair_analytic_oracle.first; + VT hess = pair_analytic_oracle.second; + + // compute the residual + VT rx = lambda - grad; + VT rs = b - A * x; + + // check stagnation + primalErrMin = std::min(primalErr, primalErrMin); + primalErr = rx.norm() / primalFactor; + NT dualErrLast = dualErr; + dualErr = rs.norm() / dualFactor; + bool feasible = f.barrier.feasible(x); + if ((dualErr > (1 - 0.9 * tConst) * dualErrLast) || + (primalErr > 10 * primalErrMin) || !feasible) + { + VT dist = f.barrier.boundary_distance(x); + NT th = options.ipmDistanceTol; + visit_lambda(dist, [&idx, th](double v, int i, int j) + { + if (v < th) + idx.push_back(i); }); + + if (idx.size() > 0) + { + break; + } + } + + // compute the step direction + VT Hinv = hess.cwiseInverse(); + solver.decompose((Tx *)Hinv.data()); + VT out(m, 1); + solver.solve((Tx *)rs.data(), (Tx *)out.data()); + VT dr1 = A.transpose() * out; + VT in = A * Hinv.cwiseProduct(rx); + solver.solve((Tx *)in.data(), (Tx *)out.data()); + + VT dr2 = A.transpose() * out; + VT dx1 = Hinv.cwiseProduct(dr1); + VT dx2 = Hinv.cwiseProduct(rx - dr2); + + // compute the step size + VT dx = dx1 + dx2; + NT tGrad = std::min(f.barrier.step_size(x, dx), 1.0); + dx = dx1 + tGrad * dx2; + NT tConst = std::min(0.99 * f.barrier.step_size(x, dx), 1.0); + tGrad = tGrad * tConst; + + // make the step + x = x + tConst * dx; + lambda = lambda - dr2; + + // update weight + VT w_vector(n, 1); + solver.leverageScoreComplement((Tx *)w_vector.data()); + + VT wNew = w_vector.cwiseMax(0) + VT::Ones(n, 1) * epsilon; + w = (w + wNew) / 2; + wp = Eigen::pow(w.array(), 0.875).matrix(); + + if (!f.barrier.feasible(x)) + { + break; + } + + // stop if converged + if (tGrad == 1) + { + fullStep = fullStep + 1; + if (fullStep > log(dualErr / options.ipmDualTol) && + fullStep > options.min_convergence_steps) + { + break; + } + } + else + { + fullStep = 0; + } + } + + SpMat C; + VT d; + if (idx.size() == 0) + { + VT dist = f.barrier.boundary_distance(x); + NT th = options.ipmDistanceTol; + visit_lambda(dist, [&idx, th](double v, int i, int j) + { + if (v < th) + idx.push_back(i); }); + } + + if (idx.size() > 0) + { + C.resize(idx.size(), n); + std::pair pboundary = f.barrier.boundary(x); + VT A_ = pboundary.first; + VT b_ = pboundary.second; + A_ = A_(idx); + std::vector sparseIdx; + for (int i = 0; i < idx.size(); i++) + { + sparseIdx.push_back(Triple(i, i, A_(i))); + } + C.setFromTriplets(sparseIdx.begin(), sparseIdx.end()); + d = b_(idx); + } + else + { + C = MT::Zero(0, n).sparseView(); + d = VT::Zero(0, 1); + } + + return std::make_tuple(x, C, d, wp); +} +#endif diff --git a/include/preprocess/crhmc/opts.h b/include/preprocess/crhmc/opts.h new file mode 100644 index 000000000..de7fe4463 --- /dev/null +++ b/include/preprocess/crhmc/opts.h @@ -0,0 +1,54 @@ +// VolEsti (volume computation and sampling library) + +// Copyright (c) 2012-2020 Vissarion Fisikopoulos +// Copyright (c) 2018-2020 Apostolos Chalkis +// Copyright (c) 2022-2022 Ioannis Iakovidis + +// Contributed and/or modified by Ioannis Iakovidis, as part of Google Summer of +// Code 2022 program. + +// Licensed under GNU LGPL.3, see LICENCE file + +// References +// Yunbum Kook, Yin Tat Lee, Ruoqi Shen, Santosh S. Vempala. "Sampling with +// Riemannian Hamiltonian +// Monte Carlo in a Constrained Space" +#ifndef OPTS_H +#define OPTS_H +template class opts { +public: + /*Preprocess options*/ + const int ipmMaxIter = 200; //Maximum number of iterations for finding the analytic and lewis center + const Type ipmDistanceTol = 1e-8; + const Type ipmDualTol = 1e-12; + int maxNZ = 30; + Type max_coord = 1e7; + bool EnableReordering = false; + const int min_convergence_steps=8; + + /*ODE options*/ + const Type implicitTol = 1e-5; + const int maxODEStep = 30; + Type initialStep = 0.2; + Type solver_accuracy_threashold=1e-2; + + /*Sampler options*/ + bool DynamicWeight = true; //Enable the use of dynamic weights for each variable when sampling + bool DynamicStepSize = true; // Enable adaptive step size that avoids low acceptance probability + bool DynamicRegularizer = true; //Enable the addition of a regularization term + + /*Dynamic step choices*/ + Type warmUpStep = 10; + Type maxConsecutiveBadStep = 10; + Type targetODEStep = 10; + Type shrinkFactor = 1.1; + Type minStepSize = 0.001; + Type effectiveStepSize = 1; + + opts() {} + void operator=(const opts &rhs) { + EnableReordering = rhs.EnableReordering; + maxNZ = rhs.maxNZ; + } +}; +#endif diff --git a/include/sos/barriers/TwoSidedBarrier.h b/include/sos/barriers/TwoSidedBarrier.h new file mode 100644 index 000000000..d888360ef --- /dev/null +++ b/include/sos/barriers/TwoSidedBarrier.h @@ -0,0 +1,157 @@ +// VolEsti (volume computation and sampling library) + +// Copyright (c) 2012-2020 Vissarion Fisikopoulos +// Copyright (c) 2018-2020 Apostolos Chalkis +// Copyright (c) 2022-2022 Ioannis Iakovidis + +// Contributed and/or modified by Ioannis Iakovidis, as part of Google Summer of +// Code 2022 program. + +// Licensed under GNU LGPL.3, see LICENCE file + +// References +// Yunbum Kook, Yin Tat Lee, Ruoqi Shen, Santosh S. Vempala. "Sampling with +// Riemannian Hamiltonian +// Monte Carlo in a Constrained Space" + +// The log barrier for the domain {lu <= x <= ub}: +// phi(x) = - sum log(x - lb) - sum log(ub - x). +#ifndef TWOSIDEDBARIER_H +#define TWOSIDEDBARIER_H + +#include "Eigen/Eigen" +#include "cartesian_geom/cartesian_kernel.h" +#include + +template class TwoSidedBarrier { + + using NT = typename Point::FT; + using MT = Eigen::Matrix; + using VT = Eigen::Matrix; + +public: + VT lb; + VT ub; + int vdim; + int n; + std::vector upperIdx; + std::vector lowerIdx; + std::vector freeIdx; + VT center; + const NT max_step = 1e16; // largest step size + VT extraHessian; //Regularization factor + + const NT inf = std::numeric_limits::infinity(); + //initialization function + void set_bound(VT const &_lb, VT const &_ub) { + + lb = _lb; + ub = _ub; + n = lb.rows(); + extraHessian = (1e-20) * VT::Ones(n); + int x1 = 0, x2 = 0, x3 = 0; + for (int i = 0; i < n; i++) { + if (lb(i) == -inf) { + upperIdx.push_back(i); + x1++; + } + if (ub(i) == inf) { + lowerIdx.push_back(i); + x2++; + } + if (ub(i) == inf && lb(i) == -inf) { + freeIdx.push_back(i); + x3++; + } + } + + VT c = (ub + lb) / 2; + + c(lowerIdx) = lb(lowerIdx) + VT::Ones(x2, 1) * 1e6; + c(upperIdx) = ub(upperIdx) - VT::Ones(x1, 1) * 1e6; + c(freeIdx) *= 0.0; + + center = c; + } + TwoSidedBarrier(VT const &_lb, VT const &_ub, int _vdim = 1) { + set_bound(_lb, _ub); + vdim = _vdim; + extraHessian = (1e-20) * VT::Ones(n); + } + TwoSidedBarrier() { vdim = 1; } + //barrier function gradient + VT gradient(VT const &x) { + return (ub - x).cwiseInverse() - (x - lb).cwiseInverse(); + } + //Return the barrier hessian with the extra Regularization + VT hessian(VT const &x) { + VT d = ((ub - x).cwiseProduct((ub - x))).cwiseInverse() + + ((x - lb).cwiseProduct((x - lb))).cwiseInverse(); + return d + extraHessian; + } + //third derivative of the barrier + VT tensor(VT const &x) { + VT d = 2 * (((ub - x).cwiseProduct((ub - x))).cwiseProduct((ub - x))) + .cwiseInverse() - + 2 * (((x - lb).cwiseProduct((x - lb))).cwiseProduct((x - lb))) + .cwiseInverse(); + return d; + } + VT quadratic_form_gradient(VT const &x, VT const &u) { + // Output the -grad of u' (hess phi(x)) u. + + return (u.cwiseProduct(u)).cwiseProduct(tensor(x)); + } + NT step_size(VT const &x, VT const &v) { + // Output the maximum step size from x with direction v. + + // check positive direction + VT temp = (v.array() > 0).select((ub - x).cwiseQuotient(v), max_step); + NT t1 = temp.minCoeff(); + + // check negative direction + temp = (v.array() < 0).select((lb - x).cwiseQuotient(v), max_step); + NT t2 = temp.minCoeff(); + + return std::min(t1, t2); + } + VT boundary_distance(VT const &x) { + // Output the distance of x with its closest boundary for each + // coordinate + + return ((x - lb).cwiseMin(ub - x)).cwiseAbs(); + } + + bool feasible(VT const &x) { + return (x.array() > lb.array() && x.array() < ub.array()).all(); + } + + std::pair analytic_center_oracle(VT const &x) { + VT g = VT::Zero(n, 1); + VT h = VT::Zero(n, 1); + return std::make_pair(g + gradient(x), h + hessian(x)); + } + + std::pair lewis_center_oracle(VT const &x, VT const &w) { + VT g = VT::Zero(n, 1); + VT h = VT::Zero(n, 1); + return std::make_pair(g + w.cwiseProduct(gradient(x)), + h + w.cwiseProduct(hessian(x))); + } + + std::pair boundary(VT const &x) { + // Output the normal at the boundary around x for each barrier. + // Assume: only 1 vector is given + + VT A = VT::Ones(x.rows(), 1); + + VT b = ub; + + b = (x.array() < center.array()).select(-lb, b); + + A = (x.array() < center.array()).select(-A, A); + + return std::make_pair(A, b); + } +}; +#endif diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index c0676f5c2..b3ff5f941 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -4,6 +4,7 @@ # Copyright (c) 2021 Vaibhav Thakkar # Contributed and/or modified by Vaibhav Thakkar +# Contributed and/or modified by Ioannis Iakovidis # Licensed under GNU LGPL.3, see LICENCE file project( VolEsti ) @@ -114,6 +115,9 @@ GetBoost() include("../external/cmake-files/LPSolve.cmake") GetLPSolve() +include("../external/cmake-files/QD.cmake") +GetQD() + # Code Coverage Configuration add_library(coverage_config INTERFACE) @@ -209,7 +213,7 @@ else () add_test(NAME test_ess COMMAND mcmc_diagnostics_test -tc=ess) add_test(NAME test_geweke COMMAND mcmc_diagnostics_test -tc=geweke) add_test(NAME test_raftery COMMAND mcmc_diagnostics_test -tc=raftery) - + add_executable (sampling_test sampling_test.cpp $) add_test(NAME test_dikin COMMAND sampling_test -tc=dikin) add_test(NAME test_john COMMAND sampling_test -tc=john) @@ -219,7 +223,7 @@ else () add_test(NAME test_grdhr COMMAND sampling_test -tc=grdhr) add_test(NAME test_gbaw COMMAND sampling_test -tc=gbaw) add_test(NAME test_ghmc COMMAND sampling_test -tc=ghmc) - + add_executable (mmcs_test mmcs_test.cpp $) add_test(NAME test_mmcs COMMAND mmcs_test -tc=mmcs) @@ -233,6 +237,18 @@ else () add_test(NAME root_finders_test_root_finders COMMAND root_finders_test -tc=root_finders) + add_executable (benchmarks_crhmc benchmarks_crhmc.cpp ) + + add_executable (crhmc_polytope_preparation_test crhmc_polytope_preparation_test.cpp $) + add_test(NAME crhmc_polytope_test_preparation + COMMAND crhmc_polytope_preparation_test -tc=test_preparation_crhmc) + add_test(NAME crhmc_test_fixed_vars + COMMAND crhmc_polytope_preparation_test -tc=test_fixed_vars_crhmc) + add_test(NAME crhmc_test_dep_vars + COMMAND crhmc_polytope_preparation_test -tc=test_dep_vars_crhmc) + add_test(NAME crhmc_test_center_computation + COMMAND crhmc_polytope_preparation_test -tc=test_center_computation) + add_executable (boundary_oracles_test boundary_oracles_test.cpp $) add_test(NAME boundary_oracles_test_h_poly_oracles COMMAND boundary_oracles_test -tc=h_poly_oracles) @@ -322,6 +338,10 @@ else () add_test(NAME order_polytope_reflection COMMAND order_polytope -tc=reflection) add_test(NAME order_polytope_vec_mult COMMAND order_polytope -tc=vec_mult) + set(ADDITIONAL_FLAGS "-DSIMD_LEN=0 -march=native -DTIME_KEEPING") + set_target_properties(benchmarks_crhmc PROPERTIES COMPILE_FLAGS ${ADDITIONAL_FLAGS}) + set_target_properties(crhmc_polytope_preparation_test PROPERTIES COMPILE_FLAGS ${ADDITIONAL_FLAGS}) + TARGET_LINK_LIBRARIES(new_volume_example ${LP_SOLVE} ${MKL_LINK} coverage_config) TARGET_LINK_LIBRARIES(new_volume_example ${LP_SOLVE} coverage_config) TARGET_LINK_LIBRARIES(volume_sob_hpolytope ${LP_SOLVE} coverage_config) @@ -340,10 +360,12 @@ else () TARGET_LINK_LIBRARIES(benchmarks_sob ${LP_SOLVE} ${MKL_LINK} coverage_config) TARGET_LINK_LIBRARIES(benchmarks_cg ${LP_SOLVE} ${MKL_LINK} coverage_config) TARGET_LINK_LIBRARIES(benchmarks_cb ${LP_SOLVE} ${MKL_LINK} coverage_config) + TARGET_LINK_LIBRARIES(benchmarks_crhmc ${LP_SOLVE} ${MKL_LINK} ${QD_LIB} coverage_config) TARGET_LINK_LIBRARIES(simple_mc_integration ${LP_SOLVE} ${MKL_LINK} coverage_config) TARGET_LINK_LIBRARIES(ode_solvers_test ${LP_SOLVE} ${IFOPT} ${IFOPT_IPOPT} ${PTHREAD} ${GMP} ${MPSOLVE} ${FFTW3} ${MKL_LINK} coverage_config) TARGET_LINK_LIBRARIES(boundary_oracles_test ${LP_SOLVE} ${IFOPT} ${IFOPT_IPOPT} ${PTHREAD} ${GMP} ${MPSOLVE} ${FFTW3} ${MKL_LINK} coverage_config) TARGET_LINK_LIBRARIES(root_finders_test ${PTHREAD} ${GMP} ${MPSOLVE} ${FFTW3} ${MKL_LINK} coverage_config) + TARGET_LINK_LIBRARIES(crhmc_polytope_preparation_test ${PTHREAD} ${GMP} ${MPSOLVE} ${FFTW3} ${MKL_LINK} ${QD_LIB} coverage_config) TARGET_LINK_LIBRARIES(logconcave_sampling_test ${LP_SOLVE} ${IFOPT} ${IFOPT_IPOPT} ${PTHREAD} ${GMP} ${MPSOLVE} ${FFTW3} ${MKL_LINK} coverage_config) TARGET_LINK_LIBRARIES(order_polytope ${LP_SOLVE} coverage_config) diff --git a/test/benchmarks_crhmc.cpp b/test/benchmarks_crhmc.cpp new file mode 100644 index 000000000..848c4d6db --- /dev/null +++ b/test/benchmarks_crhmc.cpp @@ -0,0 +1,116 @@ +// VolEsti (volume computation and sampling library) + +// Copyright (c) 2012-2020 Vissarion Fisikopoulos +// Copyright (c) 2018-2020 Apostolos Chalkis +// Copyright (c) 2022-2022 Ioannis Iakovidis + +// Contributed and/or modified by Ioannis Iakovidis, as part of Google Summer of +// Code 2022 program. + +// Licensed under GNU LGPL.3, see LICENCE file + +// References +// Yunbum Kook, Yin Tat Lee, Ruoqi Shen, Santosh S. Vempala. "Sampling with +// Riemannian Hamiltonian +// Monte Carlo in a Constrained Space" +#include "Eigen/Eigen" +#include "cartesian_geom/cartesian_kernel.h" +#include "convex_bodies/hpolytope.h" +#include "generators/known_polytope_generators.h" +#include "misc/misc.h" +#include "preprocess/crhmc/crhmc_input.h" +#include "preprocess/crhmc/crhmc_problem.h" +#include +#include +#include +using NT = double; +using Kernel = Cartesian; +using Point = typename Kernel::Point; +using Hpolytope = HPolytope; +using Input = crhmc_input; +using CrhmcProblem = crhmc_problem; +using VT = Eigen::Matrix; + +inline bool exists_check(const std::string &name) { + std::ifstream f(name.c_str()); + return f.good(); +} + +double benchmark(std::string fileName) { + std::ifstream inp; + inp.open(fileName, std::ifstream::in); + std::vector> Pin; + read_pointset(inp, Pin); + inp.close(); + Hpolytope HP(Pin); + int d = HP.dimension(); + Input input = Input(d); + input.Aineq = HP.get_mat(); + input.bineq = HP.get_vec(); + std::chrono::time_point start, end; + std::cout << "CRHMC polytope preparation for " << fileName << std::endl; + + start = std::chrono::system_clock::now(); + CrhmcProblem P = CrhmcProblem(input); + end = std::chrono::system_clock::now(); + + std::cout << "Preparation completed in time, "; + std::chrono::duration elapsed_seconds = end - start; + double preparation_time = elapsed_seconds.count(); + std::cout << preparation_time << " secs " << std::endl; + std::cout << "The resulting matrix has " << P.Asp.nonZeros() << " nonZeros" + << std::endl; + return preparation_time; +} + +int main() { + + std::cout + << "---------------CRHMC polytope preparation benchmarking---------------" + << std::endl + << std::endl; + + int d = 100000; + Input input = Input(d); + input.lb = -VT::Ones(d); + input.ub = VT::Ones(d); + std::chrono::time_point start, end; + + std::cout << "CRHMC polytope preparation 100000 dimensional Cube " + << std::endl; + + start = std::chrono::system_clock::now(); + CrhmcProblem P = CrhmcProblem(input); + end = std::chrono::system_clock::now(); + + std::cout << "Preparation completed in time, "; + std::chrono::duration elapsed_seconds = end - start; + double preparation_time = elapsed_seconds.count(); + std::cout << preparation_time << " secs " << std::endl; + std::cout << "The resulting matrix has " << P.Asp.nonZeros() << " nonZeros" + << std::endl; + assert(preparation_time < 0.5); + std::cout << "Assertion (preparation_time< 0.5 secs) passed!" << std::endl + << std::endl; + if (exists_check("../test/metabolic_full_dim/polytope_e_coli.ine")) { + preparation_time = + benchmark("../test/metabolic_full_dim/polytope_e_coli.ine"); + assert(preparation_time < 2.0); + std::cout << "Assertion (preparation_time< 2 secs) passed!" << std::endl + << std::endl; + } + if (exists_check("../test/netlib/afiro.ine")) { + preparation_time = benchmark("../test/netlib/afiro.ine"); + assert(preparation_time < 0.3); + std::cout << "Assertion (preparation_time< 0.3 secs) passed!" << std::endl + << std::endl; + } + if (exists_check("../test/metabolic_full_dim/polytope_iAB_RBC_283.ine")) { + preparation_time = + benchmark("../test/metabolic_full_dim/polytope_iAB_RBC_283.ine"); + assert(preparation_time < 400); + std::cout << "Assertion (preparation_time< 400 secs) passed!" << std::endl + << std::endl; + } + return 0; +} diff --git a/test/crhmc_polytope_preparation_test.cpp b/test/crhmc_polytope_preparation_test.cpp new file mode 100644 index 000000000..6da13269b --- /dev/null +++ b/test/crhmc_polytope_preparation_test.cpp @@ -0,0 +1,205 @@ +// VolEsti (volume computation and sampling library) + +// Copyright (c) 2012-2020 Vissarion Fisikopoulos +// Copyright (c) 2018-2020 Apostolos Chalkis +// Copyright (c) 2022-2022 Ioannis Iakovidis + +// Contributed and/or modified by Ioannis Iakovidis, as part of Google Summer of +// Code 2022 program. + +// Licensed under GNU LGPL.3, see LICENCE file + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Eigen/Eigen" +#include "cartesian_geom/cartesian_kernel.h" +#include "doctest.h" +#include "preprocess/crhmc/crhmc_input.h" +#include "preprocess/crhmc/crhmc_problem.h" +#include "ode_solvers/oracle_functors.hpp" +#include "generators/known_polytope_generators.h" +#include "convex_bodies/hpolytope.h" +#include "misc/misc.h" + +template void test_crhmc_polytope_preprocessing() { + using Kernel = Cartesian; + using Point = typename Kernel::Point; + using MT = Eigen::Matrix; + using VT = Eigen::Matrix; + using Input = crhmc_input; + using CrhmcProblem = crhmc_problem; + using PolytopeType = HPolytope; + using Opts = opts; + + std::ifstream inp; + std::vector> Pin; + std::string fileName("../test/metabolic_full_dim/polytope_e_coli.ine"); + inp.open(fileName, std::ifstream::in); + read_pointset(inp, Pin); + inp.close(); + PolytopeType HP(Pin); + Opts options = Opts(); + int d = HP.dimension(); + Input input = Input(d); + input.Aineq = HP.get_mat(); + input.bineq = HP.get_vec(); + options.EnableReordering = false; + CrhmcProblem P = CrhmcProblem(input, options); + + int m = 342; + int n = 366; + std::ifstream testdata; + std::string testDataFileName("../test/crhmc_polytope_test_output.txt"); + testdata.open(testDataFileName, std::ifstream::in); + int size; + testdata >> size; + + // CHECK(size == m); + testdata >> size; + + // CHECK(size == n); + MT A = MT(P.Asp); + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + NT Matrxidata; + testdata >> Matrxidata; + CHECK(std::abs(A(i, j) - (Matrxidata)) < 0.001); + } + } +} +template void test_crhmc_fixed_var_polytope() { + using Kernel = Cartesian; + using Point = typename Kernel::Point; + using MT = Eigen::Matrix; + using VT = Eigen::Matrix; + using Input = crhmc_input; + using CrhmcProblem = crhmc_problem; + using PolytopeType = HPolytope; + using Opts = opts; + unsigned d = 2; + MT A = MT(5, d); + A << 1, 0, -0.25, -1, 2.5, 1, 0.4, -1, -0.9, 0.5; + VT b = VT(5, 1); + b << 10, 10, 10, 10, 10; + Input input = Input(d); + input.Aineq = A; + input.bineq = b; + input.lb(1) = 10; + input.ub(1) = 10; + Opts options = Opts(); + options.EnableReordering = false; + CrhmcProblem P = CrhmcProblem(input, options); + MT Aout = MT(P.Asp); + MT Acheck = MT(5, 6); + VT a = VT(5); + a << 0.5, -0.25, 0.625, 0.2, -0.45; + Acheck << a, MT::Identity(5, 5); + int n = Aout.cols(); + int m = Aout.rows(); + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + CHECK(std::abs(Aout(i, j) - Acheck(i, j)) < 0.001); + } + } +} +template void test_crhmc_dependent_polytope() { + using Kernel = Cartesian; + using Point = typename Kernel::Point; + using MT = Eigen::Matrix; + using VT = Eigen::Matrix; + using Input = crhmc_input; + using CrhmcProblem = crhmc_problem; + using PolytopeType = HPolytope; + using Opts = opts; + unsigned d = 3; + MT Aeq = MT(3, d); + Aeq << 1, 2, 3, 1, 1, 1, 2, 3, 4; + VT beq = VT(3, 1); + beq << 10, 10, 20; + Input input = Input(d); + input.Aeq = Aeq; + input.beq = beq; + Opts options = Opts(); + options.EnableReordering = true; + CrhmcProblem P = CrhmcProblem(input, options); + CHECK(P.equations() == 2); +} + +template void test_center_computation() { + using Kernel = Cartesian; + using Point = typename Kernel::Point; + using MT = Eigen::Matrix; + using VT = Eigen::Matrix; + using Func = GaussianFunctor::FunctionFunctor; + using Grad = GaussianFunctor::GradientFunctor; + using Hess = GaussianFunctor::HessianFunctor; + using func_params=GaussianFunctor::parameters; + using Input = crhmc_input; + using CrhmcProblem = crhmc_problem; + using PolytopeType = HPolytope; + using Opts = opts; + using PolytopeType = HPolytope; + unsigned dim = 2; + Point mean=Point(VT::Ones(dim)); + mean=mean*0.5; + func_params params = func_params(mean, 0.5, 1); + Func f(params); + Grad g(params); + Hess h(params); + Opts options = Opts(); + options.EnableReordering = true; + PolytopeType HP = generate_cross(2, false); + Input input = Input(dim, f, g, h); + input.Aineq = HP.get_mat(); + input.bineq = HP.get_vec(); + CrhmcProblem P = CrhmcProblem(input, options); + VT analytic_ctr=VT(P.dimension()); + analytic_ctr<< 0.0970, 0.0970, 1.1939, 1.0000, 1.0000, 0.8061; + VT lewis_center=VT(P.dimension()); + lewis_center<< -0.0585, -0.0585, -0.1171, 0, 0, 0.1171; + for(int i=0;i void call_test_crhmc_fixed_var_polytope(){ + std::cout << "--- Testing fixed vars" << std::endl; + test_crhmc_fixed_var_polytope(); +} +template void call_test_crhmc_dependent_polytope(){ + std::cout << "--- Testing dep vars" << std::endl; + test_crhmc_dependent_polytope(); +} +template void call_test_crhmc_preprocesssing() { + std::cout << "--- Testing CRHMC data preprocessing" << std::endl; + test_crhmc_polytope_preprocessing(); +} +template void call_test_center_computation(){ + std::cout << "--- Testing CRHMC polytope-center computation" << std::endl; + test_center_computation(); +} +TEST_CASE("test_preparation_crhmc") { + call_test_crhmc_preprocesssing(); +} + +TEST_CASE("test_fixed_vars_crhmc") { + call_test_crhmc_fixed_var_polytope(); +} + +TEST_CASE("test_dep_vars_crhmc") { + call_test_crhmc_dependent_polytope(); +} + +TEST_CASE("test_center_computation"){ + call_test_center_computation(); +} diff --git a/test/crhmc_polytope_test_output.txt b/test/crhmc_polytope_test_output.txt new file mode 100644 index 000000000..6d4ffa308 --- /dev/null +++ b/test/crhmc_polytope_test_output.txt @@ -0,0 +1,343 @@ +342 366 +-0.105209 0.107012 0.504616 -0.0217608 -0.158795 0.0607718 0.029663 -0.0155544 0.179742 0.0625118 0.00840068 0.17279 0.14289 -0.578796 -0.053059 0.0668412 -0.00245974 0.152101 0.149889 -0.0442473 0.00221119 0.059206 0.0573352 0.128909 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0.014647 -0.0132836 -0.00820055 -0.0812065 -0.0492599 0.118271 0.15603 0.0188793 -0.0873765 0.0472018 0.0126745 -0.0512865 0.093865 0.0237764 -0.0616066 0.00480189 0.135507 0.0411903 0.017267 -0.0156744 0.0239233 0.0758563 0.0415845 -0.203964 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +-0.114897 0.157619 0.0191468 -0.00984175 0.163119 -0.0614544 0.00531536 0.0333849 -0.0788826 -0.0859332 -0.165124 0.0341861 0.0610335 0.221044 -0.0379432 0.0197634 0.0921928 -0.0124238 0.0565008 0.00387092 -0.0689246 -0.00621176 0.0986227 -0.0086646 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0.0167212 -0.152836 -0.071288 -0.0081594 -0.0821545 0.0614963 0.0303664 -0.015565 0.0330797 -0.0089612 0.100731 0.0138434 -0.0228157 -0.0739786 0.0876745 -0.0516496 -0.0670496 0.011936 0.0222682 0.0172847 -0.0103322 0.0804231 0.0322132 0.0743116 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0.239854 -0.0295449 0.120946 0.0346108 -0.167712 -0.00185896 -0.132735 -0.065438 0.128129 0.215442 0.152365 -0.124485 -0.097529 -0.337705 -0.156465 0.0522512 -0.0264187 -0.0117401 -0.189523 -0.0490437 0.177783 -0.180054 -0.31606 -0.236472 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +-0.016691 -0.0968698 -0.0109308 0.0157484 0.0260269 -0.0667144 -0.0581483 0.00428302 -0.026651 -0.00524175 0.158881 0.0642305 -0.106408 -0.268412 0.191445 -0.0315461 0.0167925 0.0367707 0.0470962 0.0503728 -0.0103255 -0.0149278 -0.0283306 -0.0830778 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0.146788 -0.5061 0.0803002 0.0025132 0.111325 -0.8536 0.00165992 0.42763 0.105693 -0.270732 0.341585 -0.0269298 0.450614 -0.83508 0.0524672 0.202478 0.0613072 0.0345708 -0.0391654 0.0991853 0.0737362 0.441632 -0.0440744 -0.0149749 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0.017894 -0.157846 -0.0724505 -0.0105415 -0.0747795 0.0610088 0.0173084 -0.0218503 0.038126 -0.0123728 0.100128 0.0112888 -0.0244255 -0.0697502 0.077386 -0.05838 -0.057644 0.0083565 0.0221358 0.0177644 -0.0137793 0.0798833 0.0316437 0.0524315 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0.011536 -0.0492712 -0.0114343 -0.0234302 0.072542 -0.00479528 -0.12844 -0.061822 0.0496362 -0.0335566 -0.00593652 -0.0251274 -0.0158339 0.0415901 -0.101199 -0.0662008 0.0925136 -0.0352082 -0.00130222 0.00471745 -0.033906 -0.00530984 -0.00560082 -0.215214 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +-0.0249508 -0.160816 -0.0204578 0.026661 0.00407499 -0.0526935 -0.0573591 -0.00233284 0.0066742 0.0761745 -0.0140978 -0.0419907 -0.0357286 -0.21244 0.0205331 0.203262 -0.00606965 -0.0146552 0.00180509 0.030071 -0.0164602 0.149956 0.0486705 -0.0298733 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0.0330391 0.255786 0.0381082 -0.0436506 0.0878074 -0.0560836 -0.00315676 0.0264634 -0.133301 -0.325666 0.691916 0.424886 -0.282716 -0.223887 0.683648 -0.939232 0.0914484 0.205704 0.181165 0.081207 0.0245388 -0.659536 -0.308004 -0.212818 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0.00797086 -0.0118315 0.0150858 0.0203488 -0.0399095 -0.0643345 -0.050772 0.00678105 -0.0216129 0.0101727 -0.0056027 -0.00989975 0.0189046 0.152554 0.042947 -0.0177968 -0.0118009 -0.0220661 -0.00965417 -0.00616355 -0.0124119 -0.0914935 0.0418033 0.00696685 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0.0187019 -0.00751285 -0.00484012 -0.0385627 0.044243 0.0278841 0.0708375 0.0214768 -0.0459183 0.0290157 -0.0249988 0.0855345 0.0171962 0.186288 0.0466973 0.189474 -0.129128 0.0070191 0.0298323 -0.0055977 -0.0228131 -0.035763 -0.0140368 0.0606075 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +-0.00229714 0.0007596 0.0343557 0.167613 -0.221616 0.0288708 -0.264666 -0.146768 -0.850476 0.0838124 -0.186096 0.418408 0.121989 0.841512 0.436671 -0.565667 0.689243 0.141059 0.236514 0.00193986 -0.0954548 -0.0684601 0.370785 0.375688 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +-0.00229714 0.0007596 0.0343557 0.167613 -0.221616 0.0288708 -0.264666 -0.146768 -0.850476 0.0838124 -0.186096 0.418408 0.121989 0.841512 0.436671 -0.565667 0.689243 0.141059 0.236514 0.00193986 -0.0954548 -0.0684601 0.370785 0.375688 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +-0.0317788 0.0593233 -0.0482983 -0.090615 0.0011474 -0.102828 0.0898173 0.0963225 -0.0728095 -0.0326477 0.183921 -0.068774 -0.10036 -0.196061 -0.114953 0.167456 0.243523 0.125564 -0.0874615 -0.0194338 0.213026 -0.182798 0.0887035 0.509046 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0.0221486 0.0200306 -0.0076225 -0.0491095 0.0168136 0.0527755 0.112239 0.0297318 0.0281183 0.0260995 0.0145297 0.0716647 0.0045548 0.0941354 0.116828 0.196127 0.0692455 -0.0520917 -0.0066729 -0.00435488 -0.0454188 -0.033368 -0.0171172 0.0496351 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0.00797086 -0.0118315 0.0150858 0.0203488 -0.0399095 -0.0643345 -0.050772 0.00678105 -0.0216129 0.0101727 -0.0056027 -0.00989975 0.0189046 0.152554 0.042947 -0.0177968 -0.0118009 -0.0220661 -0.00965417 -0.00616355 -0.0124119 -0.0914935 0.0418033 0.00696685 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0.012846 0.407621 -0.054606 0.0176704 -0.0437494 -0.0696787 -0.065902 0.00188838 -0.06304 0.0327984 0.113056 0.0051018 0.0306292 -0.129347 -0.0432733 0.00352357 -0.243429 0.0185318 0.0292493 0.0354892 -0.0107174 0.167311 0.0252816 0.0196713 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0.012846 0.407621 -0.054606 0.0176704 -0.0437494 -0.0696787 -0.065902 0.00188838 -0.06304 0.0327984 0.113056 0.0051018 0.0306292 -0.129347 -0.0432733 0.00352357 -0.243429 0.0185318 0.0292493 0.0354892 -0.0107174 0.167311 0.0252816 0.0196713 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0.0062684 -0.150931 0.0031414 -0.0229923 0.065045 -0.10417 -0.0091557 0.0475071 0.0227388 -0.126886 0.197876 0.191917 0.0956099 -0.187209 -0.431708 -0.00791002 -0.111058 -0.0973997 -0.110933 0.059137 0.0135335 -0.105158 0.21762 -0.189798 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0.0593762 0.0901124 0.0159273 0.0787865 0.0471287 0.0576699 -0.0514469 -0.0545585 0.0459398 0.0232667 0.287379 -0.0072611 -0.066202 0.183306 -0.127276 0.167895 0.0954687 0.111117 0.124879 -0.015779 -0.0137614 -0.0832273 0.08124 -0.0115305 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.00797086 0.0118315 -0.0150858 -0.0203488 0.0399095 0.0643345 0.050772 -0.00678105 0.0216129 -0.0101727 0.0056027 0.00989975 -0.0189046 -0.152554 -0.042947 0.0177968 0.0118009 0.0220661 0.00965417 0.00616355 0.0124119 0.0914935 -0.0418033 -0.00696685 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.00123691 0.551555 -0.0269676 0.00453913 -0.067029 -0.0494764 0.0364392 0.0429578 0.051874 0.0300964 0.136748 -0.0186618 0.0244164 -0.272044 0.0826693 0.0555214 0.166919 -0.0971665 -0.0467021 0.030304 -0.0504645 0.140598 0.0174562 0.0193355 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.0125436 -0.0535744 -0.012433 -0.0254766 0.0788778 -0.00521408 -0.139657 -0.0672217 0.0539714 -0.0364875 -0.00645504 -0.0273219 -0.0172168 0.0452227 -0.110037 -0.0719827 0.100594 -0.0382833 -0.00141592 0.00512948 -0.0368673 -0.0057736 -0.00609 -0.234011 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.00349097 -0.0474938 -0.00801167 0.0169785 0.0103856 0.0921645 -0.051995 -0.0720797 -0.061071 0.0275528 0.0304576 0.0277538 0.0272023 -0.105146 -0.0395078 -0.0285546 0.0373194 -0.0207701 -0.0170837 -0.00805446 -0.00368643 0.076489 -0.00919867 0.0974405 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.057009 -0.0466659 0.0185351 -0.025423 -0.072777 -0.0314601 0.0705071 0.0509835 -0.064727 0.116667 0.0586279 -0.0116505 -0.0999605 0.269596 0.0795024 0.00388057 -0.0444211 0.00595505 0.0099073 0.0302715 -0.00395227 0.0237064 -0.0321591 -0.0489581 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.315296 -0.0201386 0.16573 0.055304 -0.251965 -0.00060464 -0.126787 -0.0630912 0.151441 0.300369 0.205474 -0.15616 -0.123851 -0.466526 -0.169072 0.0955392 -0.0713784 -0.00189444 -0.252189 -0.0672352 0.250294 -0.237998 -0.419224 -0.231192 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.00229714 0.0007596 0.0343557 0.167613 -0.221616 0.0288708 -0.264666 -0.146768 -0.850476 0.0838124 -0.186096 0.418408 0.121989 0.841512 0.436671 -0.565667 0.689243 0.141059 0.236514 0.00193986 -0.0954548 -0.0684601 0.370785 0.375688 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.164411 0.0389513 -0.0761624 -0.0139176 0.0834596 0.00311328 0.138682 0.0677848 -0.104816 -0.130514 -0.0992568 0.0928096 0.0712072 0.208883 0.143858 -0.0089636 -0.018541 0.0215857 0.126858 0.0308522 -0.105272 0.122111 0.212895 0.241752 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.00360939 0.0294327 -0.0345698 -0.0266945 -0.0199402 0.0252243 0.0625815 0.0186786 -0.00571747 0.0338005 -0.221961 0.0069227 -0.014378 -0.394842 0.00326413 -0.0657325 -0.0127491 0.0042896 0.0153296 0.00369785 -0.0110399 -0.106227 -0.00571602 0.00935795 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.0393312 0.0397738 -0.0232798 0.0263473 0.0418393 0.0846935 -0.0337168 -0.059205 0.0123255 -0.0121444 -0.083804 0.0120997 -0.00147863 -0.240828 0.0556403 0.101562 0.157868 0.088445 0.068883 0.0342517 0.0195621 -0.0937528 0.122522 -0.144508 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.0169863 0.0125596 -0.0234828 -0.050658 -0.0448883 0.0655102 0.103943 0.0192164 0.0597565 -0.009627 -0.114374 0.0093059 0.00573585 0.580112 -0.152415 -0.133758 0.0506337 0.0496656 0.0355634 0.0387192 0.0141022 0.117994 0.00330359 0.0597165 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.017894 0.157846 0.0724505 0.0105415 0.0747795 -0.0610088 -0.0173084 0.0218503 -0.038126 0.0123728 -0.100128 -0.0112888 0.0244255 0.0697502 -0.077386 0.05838 0.057644 -0.0083565 -0.0221358 -0.0177644 0.0137793 -0.0798833 -0.0316437 -0.0524315 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.00738845 -0.0227636 -0.004319 -0.0170713 0.00336893 -0.0097288 0.0338724 0.0218006 -0.0058947 0.0489545 -0.133919 0.00893365 0.04889 -0.271785 -0.00914225 -0.083838 -0.0242036 -0.00837067 -0.0093955 0.0450002 0.00102483 -0.138475 -0.0052749 0.086772 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.0249508 -0.160816 -0.0204578 0.026661 0.00407499 -0.0526935 -0.0573591 -0.00233284 0.0066742 0.0761745 -0.0140978 -0.0419907 -0.0357286 -0.21244 0.0205331 0.203262 -0.00606965 -0.0146552 0.00180509 0.030071 -0.0164602 0.149956 0.0486705 -0.0298733 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.0521853 0.0205045 0.126117 -0.0636775 0.113714 0.0812212 0.154482 0.0366307 -0.0446404 -0.0309987 -0.0403996 -0.0811375 -0.110573 -0.187994 0.164707 -0.183881 -0.0945985 -0.0442028 -0.00593765 -0.0196445 -0.0382651 0.170391 0.167094 -0.00262001 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.0062684 0.150931 -0.0031414 0.0229923 -0.065045 0.10417 0.0091557 -0.0475071 -0.0227388 0.126886 -0.197876 -0.191917 -0.0956099 0.187209 0.431708 0.00791002 0.111058 0.0973997 0.110933 -0.059137 -0.0135335 0.105158 -0.21762 0.189798 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.317561 -0.0298088 0.163486 0.0507056 -0.237728 -0.00154576 -0.151995 -0.0752246 0.161182 0.293782 0.204309 -0.161092 -0.126958 -0.458365 -0.188934 0.0825461 -0.0532211 -0.00880456 -0.252444 -0.0663092 0.24364 -0.23904 -0.420324 -0.27343 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.02143 0.0186201 -0.0114769 0.00434825 0.0281657 0.00261874 -0.0287184 -0.0156685 0.0265328 -0.0323012 -0.0905405 0.0440105 0.028564 0.120017 0.196511 -0.00447736 0.0408463 0.0111763 -0.066868 0.00964055 0.0780442 0.128753 0.0260813 -0.0719405 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.317561 -0.0298088 0.163486 0.0507056 -0.237728 -0.00154576 -0.151995 -0.0752246 0.161182 0.293782 0.204309 -0.161092 -0.126958 -0.458365 -0.188934 0.0825461 -0.0532211 -0.00880456 -0.252444 -0.0663092 0.24364 -0.23904 -0.420324 -0.27343 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.626065 -0.0209366 0.335949 0.119805 -0.532406 0.00067296 -0.203157 -0.101915 0.283398 0.613909 0.413277 -0.302458 -0.241486 -0.949376 -0.298421 0.217064 -0.179071 0.0100314 -0.503866 -0.136322 0.513898 -0.47391 -0.83625 -0.377907 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.0361846 0.153059 0.0606895 0.00421006 0.0994283 -0.0615594 -0.0251436 0.0182079 -0.0415007 -0.0105176 -0.113698 -0.00461185 0.0302233 0.104011 -0.079236 0.044286 0.0734566 -0.0125581 -0.00653384 -0.0129833 -0.0060243 -0.06566 -0.00612945 -0.0643888 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.00797086 0.0118315 -0.0150858 -0.0203488 0.0399095 0.0643345 0.050772 -0.00678105 0.0216129 -0.0101727 0.0056027 0.00989975 -0.0189046 -0.152554 -0.042947 0.0177968 0.0118009 0.0220661 0.00965417 0.00616355 0.0124119 0.0914935 -0.0418033 -0.00696685 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.0330391 -0.255786 -0.0381082 0.0436506 -0.0878074 0.0560836 0.00315676 -0.0264634 0.133301 0.325666 -0.691916 -0.424886 0.282716 0.223887 -0.683648 0.939232 -0.0914484 -0.205704 -0.181165 -0.081207 -0.0245388 0.659536 0.308004 0.212818 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.146788 0.5061 -0.0803002 -0.0025132 -0.111325 0.8536 -0.00165992 -0.42763 -0.105693 0.270732 -0.341585 0.0269298 -0.450614 0.83508 -0.0524672 -0.202478 -0.0613072 -0.0345708 0.0391654 -0.0991853 -0.0737362 -0.441632 0.0440744 0.0149749 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.057009 0.0466659 -0.0185351 0.025423 0.072777 0.0314601 -0.0705071 -0.0509835 0.064727 -0.116667 -0.0586279 0.0116505 0.0999605 -0.269596 -0.0795024 -0.00388057 0.0444211 -0.00595505 -0.0099073 -0.0302715 0.00395227 -0.0237064 0.0321591 0.0489581 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.0249508 0.160816 0.0204578 -0.026661 -0.00407499 0.0526935 0.0573591 0.00233284 -0.0066742 -0.0761745 0.0140978 0.0419907 0.0357286 0.21244 -0.0205331 -0.203262 0.00606965 0.0146552 -0.00180509 -0.030071 0.0164602 -0.149956 -0.0486705 0.0298733 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.014647 -0.0132836 -0.00820055 -0.0812065 -0.0492599 0.118271 0.15603 0.0188793 -0.0873765 0.0472018 0.0126745 -0.0512865 0.093865 0.0237764 -0.0616066 0.00480189 0.135507 0.0411903 0.017267 -0.0156744 0.0239233 0.0758563 0.0415845 -0.203964 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.0107014 -0.282947 -0.158603 -0.0136217 -0.162567 0.125035 0.129262 0.00211324 0.0268706 -0.041705 0.178213 0.057513 -0.0236556 -0.1067 0.23799 -0.0880888 -0.163122 0.0385498 0.0765942 0.0410389 -0.0380444 0.192774 0.119127 0.265794 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.0538765 -0.0679486 0.0304163 0.053169 -0.0866844 -0.300816 0.00170208 0.151259 -0.141832 -0.0255741 -0.138628 0.103835 -0.00488049 -0.223944 0.0408046 0.00549204 0.131069 0.0651648 0.036049 -0.0367084 0.0291158 0.360462 -0.0918348 0.146476 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.0139374 0.0019538 0.096815 -0.0467398 0.104459 -0.0232648 -0.0314385 -0.00408681 -0.109487 0.106039 0.11199 -0.00521135 -0.00278614 0.0913696 -0.0890834 -0.0271566 0.214553 0.0264377 -0.0098644 0.059382 0.0363021 -0.008713 -0.102597 -0.302266 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.0188281 0.0371539 0.0221376 0.0776865 -0.00373684 -0.151858 -0.144005 0.00392678 0.0230815 0.0278905 -0.269918 0.0230353 -0.101663 0.188555 -0.0402926 0.0917589 0.0870167 0.0260595 0.0316022 0.0145474 -0.0055427 0.045793 0.0275389 0.0264563 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.0169863 -0.0125596 0.0234828 0.050658 0.0448883 -0.0655102 -0.103943 -0.0192164 -0.0597565 0.009627 0.114374 -0.0093059 -0.00573585 -0.580112 0.152415 0.133758 -0.0506337 -0.0496656 -0.0355634 -0.0387192 -0.0141022 -0.117994 -0.00330359 -0.0597165 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.0312133 0.0522324 -0.010971 -0.017902 0.0164606 0.152185 0.0467442 -0.05272 0.0525225 0.0252219 0.071514 -0.0426063 0.00830775 0.0965604 0.0170985 0.0217857 -0.0998168 -0.0195354 -0.017542 0.0166061 -0.00199351 -0.178263 0.0479929 0.00651328 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.0393313 -0.0397738 0.0232798 -0.0263473 -0.0418393 -0.0846934 0.0337168 0.0592051 -0.0123255 0.0121444 0.083804 -0.0120998 0.00147863 0.240828 -0.0556402 -0.101562 -0.157868 -0.0884448 -0.0688828 -0.0342517 -0.019562 0.0937528 -0.122522 0.144508 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.011536 0.0492712 0.0114343 0.0234302 -0.072542 0.00479528 0.12844 0.061822 -0.0496362 0.0335566 0.00593652 0.0251274 0.0158339 -0.0415901 0.101199 0.0662008 -0.0925136 0.0352082 0.00130222 -0.00471745 0.033906 0.00530984 0.00560082 0.215214 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.00349097 0.0474938 0.00801167 -0.0169785 -0.0103856 -0.0921645 0.051995 0.0720797 0.061071 -0.0275528 -0.0304576 -0.0277538 -0.0272023 0.105146 0.0395078 0.0285546 -0.0373194 0.0207701 0.0170837 0.00805446 0.00368643 -0.076489 0.00919867 -0.0974405 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.0302324 -0.417572 0.242006 0.0769848 0.186473 -0.279625 -0.229672 0.0249762 -0.00141778 0.121231 0.704332 0.0160876 0.506144 0.984456 -0.0992508 -0.144848 -0.091636 -0.101282 -0.197801 0.330419 0.0965182 -0.257984 0.003529 0.619312 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.0361846 0.153059 0.0606895 0.00421006 0.0994283 -0.0615594 -0.0251436 0.0182079 -0.0415007 -0.0105176 -0.113698 -0.00461185 0.0302233 0.104011 -0.079236 0.044286 0.0734566 -0.0125581 -0.00653384 -0.0129833 -0.0060243 -0.06566 -0.00612945 -0.0643888 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.0172563 -0.0115118 0.110982 -0.00649273 -0.064556 0.0305828 0.0137016 -0.00844058 0.0553105 0.0182573 0.0305247 0.0443503 0.0281665 -0.170702 0.00654425 0.0056388 -0.0189791 0.0411647 0.0391058 -0.007816 0.00205887 0.0312165 0.0158662 0.0483244 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.00120968 0.0149071 0.09519 0.035613 -0.0874685 0.0872281 -0.0430072 -0.0651175 -0.0581635 -0.225648 -0.104549 -0.0393503 -0.082581 -0.0396398 0.0145701 0.249086 -0.0958127 -0.055185 -0.0299238 0.0656277 -0.0252611 -0.0666004 -0.073673 0.101971 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.0134373 -0.00162347 -0.0869895 0.0455937 0.136729 -0.205499 -0.113022 0.0462384 0.14554 0.178446 0.0918748 0.090637 -0.0112838 0.0158634 0.0470365 -0.253888 -0.0396945 0.0139946 0.0126569 -0.0499532 0.00133777 -0.00925595 0.0320887 0.101992 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.0511178 0.00495464 0.176619 -0.0411445 0.122179 0.0703466 0.121166 0.0254099 -0.0323855 0.0412682 0.00379959 -0.0726085 -0.11554 0.0527774 0.0851759 -0.202112 -0.146672 -0.0657975 -0.0572315 0.0199132 -0.008566 0.183886 0.0863185 0.166449 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.00106748 0.0155499 -0.0505015 -0.0225329 -0.0084656 0.0108746 0.0333161 0.0112207 -0.012255 -0.072267 -0.0441992 -0.00852875 0.0049674 -0.240772 0.0795311 0.018231 0.0520737 0.0215947 0.051294 -0.0395578 -0.0296992 -0.0134951 0.0807755 -0.169069 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.239854 -0.0295449 0.120946 0.0346108 -0.167712 -0.00185896 -0.132735 -0.065438 0.128129 0.215442 0.152365 -0.124485 -0.097529 -0.337705 -0.156465 0.0522512 -0.0264187 -0.0117401 -0.189523 -0.0490437 0.177783 -0.180054 -0.31606 -0.236472 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.0167212 0.152836 0.071288 0.0081594 0.0821545 -0.0614963 -0.0303664 0.015565 -0.0330797 0.0089612 -0.100731 -0.0138434 0.0228157 0.0739786 -0.0876745 0.0516496 0.0670496 -0.011936 -0.0222682 -0.0172847 0.0103322 -0.0804231 -0.0322132 -0.0743116 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.0107014 0.282947 0.158603 0.0136217 0.162567 -0.125035 -0.129262 -0.00211324 -0.0268706 0.041705 -0.178213 -0.057513 0.0236556 0.1067 -0.23799 0.0880888 0.163122 -0.0385498 -0.0765942 -0.0410389 0.0380444 -0.192774 -0.119127 -0.265794 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.0077691 -0.0503246 -0.00285967 0.5978 0.0237244 0.29804 0.752652 0.227307 -0.0592823 -0.00294645 0.028752 0.0139411 0.0278628 -0.0532724 -0.0566436 -0.048783 0.0550992 0.0121187 -0.0151861 -0.00150042 0.0273048 0.0284948 -0.0384964 -0.0253788 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.0220369 0.0261488 -0.00785685 0.087563 0.015348 0.484435 -0.177472 0.169046 0.0254222 0.0161292 0.0524336 -0.0262262 0.0100906 0.0557358 0.0013722 0.00600982 -0.0568254 -0.0112078 -0.0142332 0.010848 0.0030254 -0.114124 0.0255468 -0.00113421 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.0130609 0.00092131 -0.004544 0.193435 0.0129748 -0.183231 0.600543 -0.108113 -0.00254075 0.00761955 0.0334564 -0.00940955 0.0121485 0.0141884 -0.0125955 -0.00861567 -0.0154417 -0.00226831 -0.0109018 0.0050079 0.0086335 -0.049892 0.00319794 -0.00504191 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.00897592 -0.0252275 0.00331286 0.105872 -0.00237317 0.332334 -0.221985 0.22284 -0.0279629 -0.00850965 -0.0189772 0.0168167 0.00205798 -0.0415474 -0.0139677 -0.0146255 0.0413837 0.0089395 0.0033314 -0.00584008 0.0056081 0.0642317 -0.0223488 -0.0039077 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.0538765 0.0679486 -0.0304163 -0.053169 0.0866844 0.300816 -0.00170208 -0.151259 0.141832 0.0255741 0.138628 -0.103835 0.00488049 0.223944 -0.0408046 -0.00549204 -0.131069 -0.0651648 -0.036049 0.0367084 -0.0291158 -0.360462 0.0918348 -0.146476 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.239854 -0.0295449 0.120946 0.0346108 -0.167712 -0.00185896 -0.132735 -0.065438 0.128129 0.215442 0.152365 -0.124485 -0.097529 -0.337705 -0.156465 0.0522512 -0.0264187 -0.0117401 -0.189523 -0.0490437 0.177783 -0.180054 -0.31606 -0.236472 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.0188281 -0.0371539 -0.0221376 -0.0776865 0.00373684 0.151858 0.144005 -0.00392678 -0.0230815 -0.0278905 0.269918 -0.0230353 0.101663 -0.188555 0.0402926 -0.0917589 -0.0870167 -0.0260595 -0.0316022 -0.0145474 0.0055427 -0.045793 -0.0275389 -0.0264563 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.0231141 0.0538888 -0.0165382 0.0509686 -0.133328 0.0422216 -0.0542364 -0.048229 -0.329322 -0.0440292 -0.22483 0.611064 -0.273798 0.0249693 -0.863956 -0.22673 0.00584668 -0.109366 -0.110985 -0.0529445 0.0016182 0.0674188 0.294002 -0.134788 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.0054914 -0.0133773 0.008429 0.00820945 0.0056301 -0.00694659 -0.0195241 -0.00628875 -0.0239788 0.0214838 0.0329455 -0.100465 0.0836985 0.0989468 0.270572 -0.0140259 0.0846937 0.0449739 0.0573105 0.0134786 -0.0123364 -0.0254122 -0.0271523 0.0806581 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.0169863 0.0125596 -0.0234828 -0.050658 -0.0448883 0.0655102 0.103943 0.0192164 0.0597565 -0.009627 -0.114374 0.0093059 0.00573585 0.580112 -0.152415 -0.133758 0.0506337 0.0496656 0.0355634 0.0387192 0.0141022 0.117994 0.00330359 0.0597165 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.0054914 -0.0133773 0.008429 0.00820945 0.0056301 -0.00694659 -0.0195241 -0.00628875 -0.0239788 0.0214838 0.0329455 -0.100465 0.0836985 0.0989468 0.270572 -0.0140259 0.0846937 0.0449739 0.0573105 0.0134786 -0.0123364 -0.0254122 -0.0271523 0.0806581 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.0160139 0.0983986 -0.00531736 -0.00597428 -0.147505 0.10562 0.068249 -0.0186852 0.0955809 0.00113926 0.110148 0.0430208 -0.0239135 -0.148132 0.365114 -0.130884 0.988272 -0.209728 -0.0872079 0.00660185 -0.12252 -0.00882456 0.0790144 -0.00223156 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.0181105 0.0245904 -0.0309929 0.0123377 0.0229816 0.0489644 -0.0132004 -0.0310825 -0.0825402 -0.0108307 -0.144729 -0.0688404 0.108807 0.00157736 0.35922 0.119353 -0.54994 0.562021 -0.312159 -0.0431504 -0.12582 -0.0388738 0.0324794 -0.184726 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.0105034 -0.0593219 -0.0239175 -0.0175051 0.059426 -0.073364 -0.0137323 0.0298159 -0.0427542 -0.0459374 0.00603695 -0.0960845 0.0462192 -0.0685478 -0.012064 0.00997063 -0.0823988 -0.109577 0.308288 -0.00780485 0.0821345 -0.0150581 -0.00212393 0.00506761 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.30611 0.193791 0.217775 0.391042 0.40244 0.59055 -0.536264 -0.563408 0.196644 0.48098 -0.316838 0.165028 -0.0515684 -0.00045456 -0.191126 0.666651 0.846352 0.5348 0.140711 0.590476 0.39409 -0.642062 0.333973 0.196493 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.0195587 0.0716171 0.00842105 0.0236739 -0.0479352 0.0978462 0.00713206 -0.0453571 0.00148411 0.040522 -0.0784017 0.061664 0.00818415 0.0693364 0.191675 0.0497058 -0.192571 -0.109412 0.0356325 -0.0137704 0.354955 -0.00437881 0.0183636 -0.0974306 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.0312133 -0.0522324 0.010971 0.017902 -0.0164606 -0.152185 -0.0467442 0.05272 -0.0525225 -0.0252219 -0.071514 0.0426063 -0.00830775 -0.0965604 -0.0170985 -0.0217857 0.0998168 0.0195354 0.017542 -0.0166061 0.00199351 0.178263 -0.0479929 -0.00651328 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.0393313 0.0397738 -0.0232798 0.0263473 0.0418393 0.0846934 -0.0337168 -0.0592051 0.0123255 -0.0121444 -0.083804 0.0120998 -0.00147863 -0.240828 0.0556402 0.101562 0.157868 0.0884448 0.0688828 0.0342517 0.019562 -0.0937528 0.122522 -0.144508 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.0057552 0.107985 -0.00122901 0.0479543 0.0994565 0.0725529 -0.0816571 -0.077105 0.0396072 -0.0388918 -0.152179 -0.0477091 0.0696475 0.154256 0.083649 -0.0392576 0.0657143 0.01981 0.041488 -0.0074486 -0.021678 0.0867365 -0.0790915 0.345912 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.105209 -0.107012 -0.504616 0.0217608 0.158795 -0.0607718 -0.029663 0.0155544 -0.179742 -0.0625118 -0.00840068 -0.17279 -0.14289 0.578796 0.053059 -0.0668412 0.00245974 -0.152101 -0.149889 0.0442473 -0.00221119 -0.059206 -0.0573352 -0.128909 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.014647 0.0132836 0.00820055 0.0812065 0.0492599 -0.118271 -0.15603 -0.0188793 0.0873765 -0.0472018 -0.0126745 0.0512865 -0.093865 -0.0237764 0.0616066 -0.00480189 -0.135507 -0.0411903 -0.017267 0.0156744 -0.0239233 -0.0758563 -0.0415845 0.203964 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.114897 -0.157619 -0.0191468 0.00984175 -0.163119 0.0614544 -0.00531536 -0.0333849 0.0788826 0.0859332 0.165124 -0.0341861 -0.0610335 -0.221044 0.0379432 -0.0197634 -0.0921928 0.0124238 -0.0565008 -0.00387092 0.0689246 0.00621176 -0.0986227 0.0086646 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.0167212 0.152836 0.071288 0.0081594 0.0821545 -0.0614963 -0.0303664 0.015565 -0.0330797 0.0089612 -0.100731 -0.0138434 0.0228157 0.0739786 -0.0876745 0.0516496 0.0670496 -0.011936 -0.0222682 -0.0172847 0.0103322 -0.0804231 -0.0322132 -0.0743116 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.239854 0.0295449 -0.120946 -0.0346108 0.167712 0.00185896 0.132735 0.065438 -0.128129 -0.215442 -0.152365 0.124485 0.097529 0.337705 0.156465 -0.0522512 0.0264187 0.0117401 0.189523 0.0490437 -0.177783 0.180054 0.31606 0.236472 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.016691 0.0968698 0.0109308 -0.0157484 -0.0260269 0.0667144 0.0581483 -0.00428302 0.026651 0.00524175 -0.158881 -0.0642305 0.106408 0.268412 -0.191445 0.0315461 -0.0167925 -0.0367707 -0.0470962 -0.0503728 0.0103255 0.0149278 0.0283306 0.0830778 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.146788 0.5061 -0.0803002 -0.0025132 -0.111325 0.8536 -0.00165992 -0.42763 -0.105693 0.270732 -0.341585 0.0269298 -0.450614 0.83508 -0.0524672 -0.202478 -0.0613072 -0.0345708 0.0391654 -0.0991853 -0.0737362 -0.441632 0.0440744 0.0149749 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.017894 0.157846 0.0724505 0.0105415 0.0747795 -0.0610088 -0.0173084 0.0218503 -0.038126 0.0123728 -0.100128 -0.0112888 0.0244255 0.0697502 -0.077386 0.05838 0.057644 -0.0083565 -0.0221358 -0.0177644 0.0137793 -0.0798833 -0.0316437 -0.0524315 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.011536 0.0492712 0.0114343 0.0234302 -0.072542 0.00479528 0.12844 0.061822 -0.0496362 0.0335566 0.00593652 0.0251274 0.0158339 -0.0415901 0.101199 0.0662008 -0.0925136 0.0352082 0.00130222 -0.00471745 0.033906 0.00530984 0.00560082 0.215214 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.0249508 0.160816 0.0204578 -0.026661 -0.00407499 0.0526935 0.0573591 0.00233284 -0.0066742 -0.0761745 0.0140978 0.0419907 0.0357286 0.21244 -0.0205331 -0.203262 0.00606965 0.0146552 -0.00180509 -0.030071 0.0164602 -0.149956 -0.0486705 0.0298733 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.0330391 -0.255786 -0.0381082 0.0436506 -0.0878074 0.0560836 0.00315676 -0.0264634 0.133301 0.325666 -0.691916 -0.424886 0.282716 0.223887 -0.683648 0.939232 -0.0914484 -0.205704 -0.181165 -0.081207 -0.0245388 0.659536 0.308004 0.212818 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.00797086 0.0118315 -0.0150858 -0.0203488 0.0399095 0.0643345 0.050772 -0.00678105 0.0216129 -0.0101727 0.0056027 0.00989975 -0.0189046 -0.152554 -0.042947 0.0177968 0.0118009 0.0220661 0.00965417 0.00616355 0.0124119 0.0914935 -0.0418033 -0.00696685 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.0187019 0.00751285 0.00484012 0.0385627 -0.044243 -0.0278841 -0.0708375 -0.0214768 0.0459183 -0.0290157 0.0249988 -0.0855345 -0.0171962 -0.186288 -0.0466973 -0.189474 0.129128 -0.0070191 -0.0298323 0.0055977 0.0228131 0.035763 0.0140368 -0.0606075 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.00229714 -0.0007596 -0.0343557 -0.167613 0.221616 -0.0288708 0.264666 0.146768 0.850476 -0.0838124 0.186096 -0.418408 -0.121989 -0.841512 -0.436671 0.565667 -0.689243 -0.141059 -0.236514 -0.00193986 0.0954548 0.0684601 -0.370785 -0.375688 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.00229714 -0.0007596 -0.0343557 -0.167613 0.221616 -0.0288708 0.264666 0.146768 0.850476 -0.0838124 0.186096 -0.418408 -0.121989 -0.841512 -0.436671 0.565667 -0.689243 -0.141059 -0.236514 -0.00193986 0.0954548 0.0684601 -0.370785 -0.375688 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.0317788 -0.0593233 0.0482983 0.090615 -0.0011474 0.102828 -0.0898173 -0.0963225 0.0728095 0.0326477 -0.183921 0.068774 0.10036 0.196061 0.114953 -0.167456 -0.243523 -0.125564 0.0874615 0.0194338 -0.213026 0.182798 -0.0887035 -0.509046 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.0221486 -0.0200306 0.0076225 0.0491095 -0.0168136 -0.0527755 -0.112239 -0.0297318 -0.0281183 -0.0260995 -0.0145297 -0.0716647 -0.0045548 -0.0941354 -0.116828 -0.196127 -0.0692455 0.0520917 0.0066729 0.00435488 0.0454188 0.033368 0.0171172 -0.0496351 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.00797086 0.0118315 -0.0150858 -0.0203488 0.0399095 0.0643345 0.050772 -0.00678105 0.0216129 -0.0101727 0.0056027 0.00989975 -0.0189046 -0.152554 -0.042947 0.0177968 0.0118009 0.0220661 0.00965417 0.00616355 0.0124119 0.0914935 -0.0418033 -0.00696685 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.012846 -0.407621 0.054606 -0.0176704 0.0437494 0.0696787 0.065902 -0.00188838 0.06304 -0.0327984 -0.113056 -0.0051018 -0.0306292 0.129347 0.0432733 -0.00352357 0.243429 -0.0185318 -0.0292493 -0.0354892 0.0107174 -0.167311 -0.0252816 -0.0196713 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.012846 -0.407621 0.054606 -0.0176704 0.0437494 0.0696787 0.065902 -0.00188838 0.06304 -0.0327984 -0.113056 -0.0051018 -0.0306292 0.129347 0.0432733 -0.00352357 0.243429 -0.0185318 -0.0292493 -0.0354892 0.0107174 -0.167311 -0.0252816 -0.0196713 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.0062684 0.150931 -0.0031414 0.0229923 -0.065045 0.10417 0.0091557 -0.0475071 -0.0227388 0.126886 -0.197876 -0.191917 -0.0956099 0.187209 0.431708 0.00791002 0.111058 0.0973997 0.110933 -0.059137 -0.0135335 0.105158 -0.21762 0.189798 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.0593762 -0.0901124 -0.0159273 -0.0787865 -0.0471287 -0.0576699 0.0514469 0.0545585 -0.0459398 -0.0232667 -0.287379 0.0072611 0.066202 -0.183306 0.127276 -0.167895 -0.0954687 -0.111117 -0.124879 0.015779 0.0137614 0.0832273 -0.08124 0.0115305 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.00797086 -0.0118315 0.0150858 0.0203488 -0.0399095 -0.0643345 -0.050772 0.00678105 -0.0216129 0.0101727 -0.0056027 -0.00989975 0.0189046 0.152554 0.042947 -0.0177968 -0.0118009 -0.0220661 -0.00965417 -0.00616355 -0.0124119 -0.0914935 0.0418033 0.00696685 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.00123691 -0.551555 0.0269676 -0.00453913 0.067029 0.0494764 -0.0364392 -0.0429578 -0.051874 -0.0300964 -0.136748 0.0186618 -0.0244164 0.272044 -0.0826693 -0.0555214 -0.166919 0.0971665 0.0467021 -0.030304 0.0504645 -0.140598 -0.0174562 -0.0193355 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.0125436 0.0535744 0.012433 0.0254766 -0.0788778 0.00521408 0.139657 0.0672217 -0.0539714 0.0364875 0.00645504 0.0273219 0.0172168 -0.0452227 0.110037 0.0719827 -0.100594 0.0382833 0.00141592 -0.00512948 0.0368673 0.0057736 0.00609 0.234011 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.00349097 0.0474938 0.00801167 -0.0169785 -0.0103856 -0.0921645 0.051995 0.0720797 0.061071 -0.0275528 -0.0304576 -0.0277538 -0.0272023 0.105146 0.0395078 0.0285546 -0.0373194 0.0207701 0.0170837 0.00805446 0.00368643 -0.076489 0.00919867 -0.0974405 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.057009 0.0466659 -0.0185351 0.025423 0.072777 0.0314601 -0.0705071 -0.0509835 0.064727 -0.116667 -0.0586279 0.0116505 0.0999605 -0.269596 -0.0795024 -0.00388057 0.0444211 -0.00595505 -0.0099073 -0.0302715 0.00395227 -0.0237064 0.0321591 0.0489581 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.315296 0.0201386 -0.16573 -0.055304 0.251965 0.00060464 0.126787 0.0630912 -0.151441 -0.300369 -0.205474 0.15616 0.123851 0.466526 0.169072 -0.0955392 0.0713784 0.00189444 0.252189 0.0672352 -0.250294 0.237998 0.419224 0.231192 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.00229714 -0.0007596 -0.0343557 -0.167613 0.221616 -0.0288708 0.264666 0.146768 0.850476 -0.0838124 0.186096 -0.418408 -0.121989 -0.841512 -0.436671 0.565667 -0.689243 -0.141059 -0.236514 -0.00193986 0.0954548 0.0684601 -0.370785 -0.375688 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.164411 -0.0389513 0.0761624 0.0139176 -0.0834596 -0.00311328 -0.138682 -0.0677848 0.104816 0.130514 0.0992568 -0.0928096 -0.0712072 -0.208883 -0.143858 0.0089636 0.018541 -0.0215857 -0.126858 -0.0308522 0.105272 -0.122111 -0.212895 -0.241752 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.00360939 -0.0294327 0.0345698 0.0266945 0.0199402 -0.0252243 -0.0625815 -0.0186786 0.00571747 -0.0338005 0.221961 -0.0069227 0.014378 0.394842 -0.00326413 0.0657325 0.0127491 -0.0042896 -0.0153296 -0.00369785 0.0110399 0.106227 0.00571602 -0.00935795 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.0393312 -0.0397738 0.0232798 -0.0263473 -0.0418393 -0.0846935 0.0337168 0.059205 -0.0123255 0.0121444 0.083804 -0.0120997 0.00147863 0.240828 -0.0556403 -0.101562 -0.157868 -0.088445 -0.068883 -0.0342517 -0.0195621 0.0937528 -0.122522 0.144508 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.0169863 -0.0125596 0.0234828 0.050658 0.0448883 -0.0655102 -0.103943 -0.0192164 -0.0597565 0.009627 0.114374 -0.0093059 -0.00573585 -0.580112 0.152415 0.133758 -0.0506337 -0.0496656 -0.0355634 -0.0387192 -0.0141022 -0.117994 -0.00330359 -0.0597165 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.017894 -0.157846 -0.0724505 -0.0105415 -0.0747795 0.0610088 0.0173084 -0.0218503 0.038126 -0.0123728 0.100128 0.0112888 -0.0244255 -0.0697502 0.077386 -0.05838 -0.057644 0.0083565 0.0221358 0.0177644 -0.0137793 0.0798833 0.0316437 0.0524315 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.00738845 0.0227636 0.004319 0.0170713 -0.00336893 0.0097288 -0.0338724 -0.0218006 0.0058947 -0.0489545 0.133919 -0.00893365 -0.04889 0.271785 0.00914225 0.083838 0.0242036 0.00837067 0.0093955 -0.0450002 -0.00102483 0.138475 0.0052749 -0.086772 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.0249508 0.160816 0.0204578 -0.026661 -0.00407499 0.0526935 0.0573591 0.00233284 -0.0066742 -0.0761745 0.0140978 0.0419907 0.0357286 0.21244 -0.0205331 -0.203262 0.00606965 0.0146552 -0.00180509 -0.030071 0.0164602 -0.149956 -0.0486705 0.0298733 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.0521853 -0.0205045 -0.126117 0.0636775 -0.113714 -0.0812212 -0.154482 -0.0366307 0.0446404 0.0309987 0.0403996 0.0811375 0.110573 0.187994 -0.164707 0.183881 0.0945985 0.0442028 0.00593765 0.0196445 0.0382651 -0.170391 -0.167094 0.00262001 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.0062684 -0.150931 0.0031414 -0.0229923 0.065045 -0.10417 -0.0091557 0.0475071 0.0227388 -0.126886 0.197876 0.191917 0.0956099 -0.187209 -0.431708 -0.00791002 -0.111058 -0.0973997 -0.110933 0.059137 0.0135335 -0.105158 0.21762 -0.189798 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.317561 0.0298088 -0.163486 -0.0507056 0.237728 0.00154576 0.151995 0.0752246 -0.161182 -0.293782 -0.204309 0.161092 0.126958 0.458365 0.188934 -0.0825461 0.0532211 0.00880456 0.252444 0.0663092 -0.24364 0.23904 0.420324 0.27343 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.02143 -0.0186201 0.0114769 -0.00434825 -0.0281657 -0.00261874 0.0287184 0.0156685 -0.0265328 0.0323012 0.0905405 -0.0440105 -0.028564 -0.120017 -0.196511 0.00447736 -0.0408463 -0.0111763 0.066868 -0.00964055 -0.0780442 -0.128753 -0.0260813 0.0719405 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.317561 0.0298088 -0.163486 -0.0507056 0.237728 0.00154576 0.151995 0.0752246 -0.161182 -0.293782 -0.204309 0.161092 0.126958 0.458365 0.188934 -0.0825461 0.0532211 0.00880456 0.252444 0.0663092 -0.24364 0.23904 0.420324 0.27343 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.626065 0.0209366 -0.335949 -0.119805 0.532406 -0.00067296 0.203157 0.101915 -0.283398 -0.613909 -0.413277 0.302458 0.241486 0.949376 0.298421 -0.217064 0.179071 -0.0100314 0.503866 0.136322 -0.513898 0.47391 0.83625 0.377907 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.0361846 -0.153059 -0.0606895 -0.00421006 -0.0994283 0.0615594 0.0251436 -0.0182079 0.0415007 0.0105176 0.113698 0.00461185 -0.0302233 -0.104011 0.079236 -0.044286 -0.0734566 0.0125581 0.00653384 0.0129833 0.0060243 0.06566 0.00612945 0.0643888 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.00797086 -0.0118315 0.0150858 0.0203488 -0.0399095 -0.0643345 -0.050772 0.00678105 -0.0216129 0.0101727 -0.0056027 -0.00989975 0.0189046 0.152554 0.042947 -0.0177968 -0.0118009 -0.0220661 -0.00965417 -0.00616355 -0.0124119 -0.0914935 0.0418033 0.00696685 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.0330391 0.255786 0.0381082 -0.0436506 0.0878074 -0.0560836 -0.00315676 0.0264634 -0.133301 -0.325666 0.691916 0.424886 -0.282716 -0.223887 0.683648 -0.939232 0.0914484 0.205704 0.181165 0.081207 0.0245388 -0.659536 -0.308004 -0.212818 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.146788 -0.5061 0.0803002 0.0025132 0.111325 -0.8536 0.00165992 0.42763 0.105693 -0.270732 0.341585 -0.0269298 0.450614 -0.83508 0.0524672 0.202478 0.0613072 0.0345708 -0.0391654 0.0991853 0.0737362 0.441632 -0.0440744 -0.0149749 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.057009 -0.0466659 0.0185351 -0.025423 -0.072777 -0.0314601 0.0705071 0.0509835 -0.064727 0.116667 0.0586279 -0.0116505 -0.0999605 0.269596 0.0795024 0.00388057 -0.0444211 0.00595505 0.0099073 0.0302715 -0.00395227 0.0237064 -0.0321591 -0.0489581 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.0249508 -0.160816 -0.0204578 0.026661 0.00407499 -0.0526935 -0.0573591 -0.00233284 0.0066742 0.0761745 -0.0140978 -0.0419907 -0.0357286 -0.21244 0.0205331 0.203262 -0.00606965 -0.0146552 0.00180509 0.030071 -0.0164602 0.149956 0.0486705 -0.0298733 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.014647 0.0132836 0.00820055 0.0812065 0.0492599 -0.118271 -0.15603 -0.0188793 0.0873765 -0.0472018 -0.0126745 0.0512865 -0.093865 -0.0237764 0.0616066 -0.00480189 -0.135507 -0.0411903 -0.017267 0.0156744 -0.0239233 -0.0758563 -0.0415845 0.203964 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.0107014 0.282947 0.158603 0.0136217 0.162567 -0.125035 -0.129262 -0.00211324 -0.0268706 0.041705 -0.178213 -0.057513 0.0236556 0.1067 -0.23799 0.0880888 0.163122 -0.0385498 -0.0765942 -0.0410389 0.0380444 -0.192774 -0.119127 -0.265794 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.0538765 0.0679486 -0.0304163 -0.053169 0.0866844 0.300816 -0.00170208 -0.151259 0.141832 0.0255741 0.138628 -0.103835 0.00488049 0.223944 -0.0408046 -0.00549204 -0.131069 -0.0651648 -0.036049 0.0367084 -0.0291158 -0.360462 0.0918348 -0.146476 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.0139374 -0.0019538 -0.096815 0.0467398 -0.104459 0.0232648 0.0314385 0.00408681 0.109487 -0.106039 -0.11199 0.00521135 0.00278614 -0.0913696 0.0890834 0.0271566 -0.214553 -0.0264377 0.0098644 -0.059382 -0.0363021 0.008713 0.102597 0.302266 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.0188281 -0.0371539 -0.0221376 -0.0776865 0.00373684 0.151858 0.144005 -0.00392678 -0.0230815 -0.0278905 0.269918 -0.0230353 0.101663 -0.188555 0.0402926 -0.0917589 -0.0870167 -0.0260595 -0.0316022 -0.0145474 0.0055427 -0.045793 -0.0275389 -0.0264563 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.0169863 0.0125596 -0.0234828 -0.050658 -0.0448883 0.0655102 0.103943 0.0192164 0.0597565 -0.009627 -0.114374 0.0093059 0.00573585 0.580112 -0.152415 -0.133758 0.0506337 0.0496656 0.0355634 0.0387192 0.0141022 0.117994 0.00330359 0.0597165 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.0312133 -0.0522324 0.010971 0.017902 -0.0164606 -0.152185 -0.0467442 0.05272 -0.0525225 -0.0252219 -0.071514 0.0426063 -0.00830775 -0.0965604 -0.0170985 -0.0217857 0.0998168 0.0195354 0.017542 -0.0166061 0.00199351 0.178263 -0.0479929 -0.00651328 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.0393313 0.0397738 -0.0232798 0.0263473 0.0418393 0.0846934 -0.0337168 -0.0592051 0.0123255 -0.0121444 -0.083804 0.0120998 -0.00147863 -0.240828 0.0556402 0.101562 0.157868 0.0884448 0.0688828 0.0342517 0.019562 -0.0937528 0.122522 -0.144508 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.011536 -0.0492712 -0.0114343 -0.0234302 0.072542 -0.00479528 -0.12844 -0.061822 0.0496362 -0.0335566 -0.00593652 -0.0251274 -0.0158339 0.0415901 -0.101199 -0.0662008 0.0925136 -0.0352082 -0.00130222 0.00471745 -0.033906 -0.00530984 -0.00560082 -0.215214 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.00349097 -0.0474938 -0.00801167 0.0169785 0.0103856 0.0921645 -0.051995 -0.0720797 -0.061071 0.0275528 0.0304576 0.0277538 0.0272023 -0.105146 -0.0395078 -0.0285546 0.0373194 -0.0207701 -0.0170837 -0.00805446 -0.00368643 0.076489 -0.00919867 0.0974405 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.0302324 0.417572 -0.242006 -0.0769848 -0.186473 0.279625 0.229672 -0.0249762 0.00141778 -0.121231 -0.704332 -0.0160876 -0.506144 -0.984456 0.0992508 0.144848 0.091636 0.101282 0.197801 -0.330419 -0.0965182 0.257984 -0.003529 -0.619312 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.0361846 -0.153059 -0.0606895 -0.00421006 -0.0994283 0.0615594 0.0251436 -0.0182079 0.0415007 0.0105176 0.113698 0.00461185 -0.0302233 -0.104011 0.079236 -0.044286 -0.0734566 0.0125581 0.00653384 0.0129833 0.0060243 0.06566 0.00612945 0.0643888 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.0172563 0.0115118 -0.110982 0.00649273 0.064556 -0.0305828 -0.0137016 0.00844058 -0.0553105 -0.0182573 -0.0305247 -0.0443503 -0.0281665 0.170702 -0.00654425 -0.0056388 0.0189791 -0.0411647 -0.0391058 0.007816 -0.00205887 -0.0312165 -0.0158662 -0.0483244 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.00120968 -0.0149071 -0.09519 -0.035613 0.0874685 -0.0872281 0.0430072 0.0651175 0.0581635 0.225648 0.104549 0.0393503 0.082581 0.0396398 -0.0145701 -0.249086 0.0958127 0.055185 0.0299238 -0.0656277 0.0252611 0.0666004 0.073673 -0.101971 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.0134373 0.00162347 0.0869895 -0.0455937 -0.136729 0.205499 0.113022 -0.0462384 -0.14554 -0.178446 -0.0918748 -0.090637 0.0112838 -0.0158634 -0.0470365 0.253888 0.0396945 -0.0139946 -0.0126569 0.0499532 -0.00133777 0.00925595 -0.0320887 -0.101992 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.0511178 -0.00495464 -0.176619 0.0411445 -0.122179 -0.0703466 -0.121166 -0.0254099 0.0323855 -0.0412682 -0.00379959 0.0726085 0.11554 -0.0527774 -0.0851759 0.202112 0.146672 0.0657975 0.0572315 -0.0199132 0.008566 -0.183886 -0.0863185 -0.166449 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.00106748 -0.0155499 0.0505015 0.0225329 0.0084656 -0.0108746 -0.0333161 -0.0112207 0.012255 0.072267 0.0441992 0.00852875 -0.0049674 0.240772 -0.0795311 -0.018231 -0.0520737 -0.0215947 -0.051294 0.0395578 0.0296992 0.0134951 -0.0807755 0.169069 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.239854 0.0295449 -0.120946 -0.0346108 0.167712 0.00185896 0.132735 0.065438 -0.128129 -0.215442 -0.152365 0.124485 0.097529 0.337705 0.156465 -0.0522512 0.0264187 0.0117401 0.189523 0.0490437 -0.177783 0.180054 0.31606 0.236472 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.0167212 -0.152836 -0.071288 -0.0081594 -0.0821545 0.0614963 0.0303664 -0.015565 0.0330797 -0.0089612 0.100731 0.0138434 -0.0228157 -0.0739786 0.0876745 -0.0516496 -0.0670496 0.011936 0.0222682 0.0172847 -0.0103322 0.0804231 0.0322132 0.0743116 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.0107014 -0.282947 -0.158603 -0.0136217 -0.162567 0.125035 0.129262 0.00211324 0.0268706 -0.041705 0.178213 0.057513 -0.0236556 -0.1067 0.23799 -0.0880888 -0.163122 0.0385498 0.0765942 0.0410389 -0.0380444 0.192774 0.119127 0.265794 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.0077691 0.0503246 0.00285967 -0.5978 -0.0237244 -0.29804 -0.752652 -0.227307 0.0592823 0.00294645 -0.028752 -0.0139411 -0.0278628 0.0532724 0.0566436 0.048783 -0.0550992 -0.0121187 0.0151861 0.00150042 -0.0273048 -0.0284948 0.0384964 0.0253788 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.0220369 -0.0261488 0.00785685 -0.087563 -0.015348 -0.484435 0.177472 -0.169046 -0.0254222 -0.0161292 -0.0524336 0.0262262 -0.0100906 -0.0557358 -0.0013722 -0.00600982 0.0568254 0.0112078 0.0142332 -0.010848 -0.0030254 0.114124 -0.0255468 0.00113421 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.0130609 -0.00092131 0.004544 -0.193435 -0.0129748 0.183231 -0.600543 0.108113 0.00254075 -0.00761955 -0.0334564 0.00940955 -0.0121485 -0.0141884 0.0125955 0.00861567 0.0154417 0.00226831 0.0109018 -0.0050079 -0.0086335 0.049892 -0.00319794 0.00504191 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.00897592 0.0252275 -0.00331286 -0.105872 0.00237317 -0.332334 0.221985 -0.22284 0.0279629 0.00850965 0.0189772 -0.0168167 -0.00205798 0.0415474 0.0139677 0.0146255 -0.0413837 -0.0089395 -0.0033314 0.00584008 -0.0056081 -0.0642317 0.0223488 0.0039077 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.0538765 -0.0679486 0.0304163 0.053169 -0.0866844 -0.300816 0.00170208 0.151259 -0.141832 -0.0255741 -0.138628 0.103835 -0.00488049 -0.223944 0.0408046 0.00549204 0.131069 0.0651648 0.036049 -0.0367084 0.0291158 0.360462 -0.0918348 0.146476 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.239854 0.0295449 -0.120946 -0.0346108 0.167712 0.00185896 0.132735 0.065438 -0.128129 -0.215442 -0.152365 0.124485 0.097529 0.337705 0.156465 -0.0522512 0.0264187 0.0117401 0.189523 0.0490437 -0.177783 0.180054 0.31606 0.236472 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.0188281 0.0371539 0.0221376 0.0776865 -0.00373684 -0.151858 -0.144005 0.00392678 0.0230815 0.0278905 -0.269918 0.0230353 -0.101663 0.188555 -0.0402926 0.0917589 0.0870167 0.0260595 0.0316022 0.0145474 -0.0055427 0.045793 0.0275389 0.0264563 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.0231141 -0.0538888 0.0165382 -0.0509686 0.133328 -0.0422216 0.0542364 0.048229 0.329322 0.0440292 0.22483 -0.611064 0.273798 -0.0249693 0.863956 0.22673 -0.00584668 0.109366 0.110985 0.0529445 -0.0016182 -0.0674188 -0.294002 0.134788 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.0054914 0.0133773 -0.008429 -0.00820945 -0.0056301 0.00694659 0.0195241 0.00628875 0.0239788 -0.0214838 -0.0329455 0.100465 -0.0836985 -0.0989468 -0.270572 0.0140259 -0.0846937 -0.0449739 -0.0573105 -0.0134786 0.0123364 0.0254122 0.0271523 -0.0806581 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.0169863 -0.0125596 0.0234828 0.050658 0.0448883 -0.0655102 -0.103943 -0.0192164 -0.0597565 0.009627 0.114374 -0.0093059 -0.00573585 -0.580112 0.152415 0.133758 -0.0506337 -0.0496656 -0.0355634 -0.0387192 -0.0141022 -0.117994 -0.00330359 -0.0597165 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.0054914 0.0133773 -0.008429 -0.00820945 -0.0056301 0.00694659 0.0195241 0.00628875 0.0239788 -0.0214838 -0.0329455 0.100465 -0.0836985 -0.0989468 -0.270572 0.0140259 -0.0846937 -0.0449739 -0.0573105 -0.0134786 0.0123364 0.0254122 0.0271523 -0.0806581 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.0160139 -0.0983986 0.00531736 0.00597428 0.147505 -0.10562 -0.068249 0.0186852 -0.0955809 -0.00113926 -0.110148 -0.0430208 0.0239135 0.148132 -0.365114 0.130884 -0.988272 0.209728 0.0872079 -0.00660185 0.12252 0.00882456 -0.0790144 0.00223156 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.0181105 -0.0245904 0.0309929 -0.0123377 -0.0229816 -0.0489644 0.0132004 0.0310825 0.0825402 0.0108307 0.144729 0.0688404 -0.108807 -0.00157736 -0.35922 -0.119353 0.54994 -0.562021 0.312159 0.0431504 0.12582 0.0388738 -0.0324794 0.184726 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.0105034 0.0593219 0.0239175 0.0175051 -0.059426 0.073364 0.0137323 -0.0298159 0.0427542 0.0459374 -0.00603695 0.0960845 -0.0462192 0.0685478 0.012064 -0.00997063 0.0823988 0.109577 -0.308288 0.00780485 -0.0821345 0.0150581 0.00212393 -0.00506761 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.30611 -0.193791 -0.217775 -0.391042 -0.40244 -0.59055 0.536264 0.563408 -0.196644 -0.48098 0.316838 -0.165028 0.0515684 0.00045456 0.191126 -0.666651 -0.846352 -0.5348 -0.140711 -0.590476 -0.39409 0.642062 -0.333973 -0.196493 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.0195587 -0.0716171 -0.00842105 -0.0236739 0.0479352 -0.0978462 -0.00713206 0.0453571 -0.00148411 -0.040522 0.0784017 -0.061664 -0.00818415 -0.0693364 -0.191675 -0.0497058 0.192571 0.109412 -0.0356325 0.0137704 -0.354955 0.00437881 -0.0183636 0.0974306 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.0312133 0.0522324 -0.010971 -0.017902 0.0164606 0.152185 0.0467442 -0.05272 0.0525225 0.0252219 0.071514 -0.0426063 0.00830775 0.0965604 0.0170985 0.0217857 -0.0998168 -0.0195354 -0.017542 0.0166061 -0.00199351 -0.178263 0.0479929 0.00651328 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.0393313 -0.0397738 0.0232798 -0.0263473 -0.0418393 -0.0846934 0.0337168 0.0592051 -0.0123255 0.0121444 0.083804 -0.0120998 0.00147863 0.240828 -0.0556402 -0.101562 -0.157868 -0.0884448 -0.0688828 -0.0342517 -0.019562 0.0937528 -0.122522 0.144508 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.0057552 -0.107985 0.00122901 -0.0479543 -0.0994565 -0.0725529 0.0816571 0.077105 -0.0396072 0.0388918 0.152179 0.0477091 -0.0696475 -0.154256 -0.083649 0.0392576 -0.0657143 -0.01981 -0.041488 0.0074486 0.021678 -0.0867365 0.0790915 -0.345912 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 +1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 From 9fbc827d451331f7303bfa35c88c69a74b3e27df Mon Sep 17 00:00:00 2001 From: Vissarion Fisikopoulos Date: Sat, 29 Oct 2022 20:19:19 +0100 Subject: [PATCH 05/20] Update ubuntu-based github actions. --- .github/workflows/cmake-clang.yml | 22 ++++++++++++++++------ .github/workflows/cmake-gcc.yml | 19 ++++++++++++++----- 2 files changed, 30 insertions(+), 11 deletions(-) diff --git a/.github/workflows/cmake-clang.yml b/.github/workflows/cmake-clang.yml index 028248af4..6a4a8518c 100644 --- a/.github/workflows/cmake-clang.yml +++ b/.github/workflows/cmake-clang.yml @@ -1,7 +1,7 @@ ############################################################################## # GitHub Actions Workflow for volesti to build tests with GCC # -# Copyright (c) 2020-2021 Vissarion Fisikopoulos +# Copyright (c) 2020-2022 Vissarion Fisikopoulos # # Licensed under GNU LGPL.3, see LICENCE file ############################################################################## @@ -11,19 +11,29 @@ on: [push, pull_request] jobs: build: - name: ${{ matrix.compilers }} + name: ${{ matrix.config.os }} - ${{ matrix.config.compiler }} strategy: fail-fast: false matrix: - compilers: [clang++-6.0, clang++-7, clang++-8, clang++-9, clang++-10] - runs-on: ubuntu-latest + config: + - {os: ubuntu-22.04, compiler_pkg: clang-11, compiler: clang++-11} + - {os: ubuntu-22.04, compiler_pkg: clang-12, compiler: clang++-12} + - {os: ubuntu-22.04, compiler_pkg: clang-13, compiler: clang++-13} + - {os: ubuntu-22.04, compiler_pkg: clang-14, compiler: clang++-14} + - {os: ubuntu-22.04, compiler_pkg: clang-15, compiler: clang++-15} + - {os: ubuntu-20.04, compiler_pkg: clang-8, compiler: clang++-8} + - {os: ubuntu-20.04, compiler_pkg: clang-9, compiler: clang++-9} + - {os: ubuntu-20.04, compiler_pkg: clang-10, compiler: clang++-10} + - {os: ubuntu-20.04, compiler_pkg: clang-11, compiler: clang++-11} + - {os: ubuntu-20.04, compiler_pkg: clang-12, compiler: clang++-12} + runs-on: ${{ matrix.config.os }} steps: - uses: actions/checkout@v1 - run: sudo apt-get update || true; - sudo apt-get install clang-6.0 clang-7 clang-8 clang-9 clang-10 lp-solve; + sudo apt-get install ${{ matrix.config.compiler_pkg }} lp-solve; rm -rf build; mkdir build; cd build; - cmake -D CMAKE_CXX_COMPILER=${{ matrix.compilers }} -D CMAKE_CXX_FLAGS=-fsanitize=memory -D CMAKE_CXX_FLAGS=-fsanitize=undefined -D CMAKE_CXX_FLAGS=-g -D DISABLE_NLP_ORACLES=ON -D USE_MKL=OFF ../test; + cmake -D CMAKE_CXX_COMPILER=${{ matrix.config.compiler }} -D CMAKE_CXX_FLAGS=-fsanitize=memory -D CMAKE_CXX_FLAGS=-fsanitize=undefined -D CMAKE_CXX_FLAGS=-g -D DISABLE_NLP_ORACLES=ON -D USE_MKL=OFF ../test; make; ctest --verbose; diff --git a/.github/workflows/cmake-gcc.yml b/.github/workflows/cmake-gcc.yml index 73cca0916..704df9250 100644 --- a/.github/workflows/cmake-gcc.yml +++ b/.github/workflows/cmake-gcc.yml @@ -11,19 +11,28 @@ on: [push, pull_request] jobs: build: - name: ${{ matrix.compilers }} + name: ${{ matrix.config.os }} - ${{ matrix.config.compiler }} strategy: fail-fast: false matrix: - compilers: [g++-5, g++-6, g++-7, g++-8, g++-9, g++-10] - runs-on: ubuntu-18.04 + config: + - {os: ubuntu-22.04, compiler: g++-9} + - {os: ubuntu-22.04, compiler: g++-10} + - {os: ubuntu-22.04, compiler: g++-11} + - {os: ubuntu-22.04, compiler: g++-12} + - {os: ubuntu-22.04, compiler: g++-13} + - {os: ubuntu-20.04, compiler: g++-7} + - {os: ubuntu-20.04, compiler: g++-8} + - {os: ubuntu-20.04, compiler: g++-9} + - {os: ubuntu-20.04, compiler: g++-10} + runs-on: ${{ matrix.config.os }} steps: - uses: actions/checkout@v1 - run: sudo apt-get update || true; - sudo apt-get install ${{ matrix.compilers }} lp-solve; + sudo apt-get install ${{ matrix.config.compiler }} lp-solve; rm -rf build; mkdir build; cd build; - cmake -D CMAKE_CXX_COMPILER=${{ matrix.compilers }} -D DISABLE_NLP_ORACLES=ON -D USE_MKL=OFF ../test; + cmake -D CMAKE_CXX_COMPILER=${{ matrix.config.compiler }} -D DISABLE_NLP_ORACLES=ON -D USE_MKL=OFF ../test; make; ctest --verbose; From 6733390d9d05b847389eda1e9a46069eb3cd2430 Mon Sep 17 00:00:00 2001 From: Vissarion Fisikopoulos Date: Sat, 29 Oct 2022 20:19:19 +0100 Subject: [PATCH 06/20] Update doctest to version 2.4.9 --- test/doctest.h | 9121 ++++++++++++++++++++++++++++-------------------- 1 file changed, 5338 insertions(+), 3783 deletions(-) diff --git a/test/doctest.h b/test/doctest.h index e160b7f78..e9752304c 100644 --- a/test/doctest.h +++ b/test/doctest.h @@ -1,25 +1,25 @@ -// ====================================================================== +// ====================================================================== lgtm [cpp/missing-header-guard] // == DO NOT MODIFY THIS FILE BY HAND - IT IS AUTO GENERATED BY CMAKE! == // ====================================================================== // // doctest.h - the lightest feature-rich C++ single-header testing framework for unit tests and TDD // -// Copyright (c) 2016-2018 Viktor Kirilov +// Copyright (c) 2016-2021 Viktor Kirilov // // Distributed under the MIT Software License // See accompanying file LICENSE.txt or copy at // https://opensource.org/licenses/MIT // // The documentation can be found at the library's page: -// https://github.com/onqtam/doctest/blob/master/doc/markdown/readme.md +// https://github.com/doctest/doctest/blob/master/doc/markdown/readme.md // // ================================================================================================= // ================================================================================================= // ================================================================================================= // -// The library is heavily influenced by Catch - https://github.com/philsquared/Catch +// The library is heavily influenced by Catch - https://github.com/catchorg/Catch2 // which uses the Boost Software License - Version 1.0 -// see here - https://github.com/philsquared/Catch/blob/master/LICENSE.txt +// see here - https://github.com/catchorg/Catch2/blob/master/LICENSE.txt // // The concept of subcases (sections in Catch) and expression decomposition are from there. // Some parts of the code are taken directly: @@ -29,17 +29,12 @@ // - breaking into a debugger // - signal / SEH handling // - timer +// - XmlWriter class - thanks to Phil Nash for allowing the direct reuse (AKA copy/paste) // // The expression decomposing templates are taken from lest - https://github.com/martinmoene/lest // which uses the Boost Software License - Version 1.0 // see here - https://github.com/martinmoene/lest/blob/master/LICENSE.txt // -// The type list and the foreach algorithm on it for C++98 are taken from Loki -// - http://loki-lib.sourceforge.net/ -// - https://en.wikipedia.org/wiki/Loki_%28C%2B%2B%29 -// - https://github.com/snaewe/loki-lib -// which uses the MIT Software License -// // ================================================================================================= // ================================================================================================= // ================================================================================================= @@ -51,10 +46,18 @@ // == VERSION ====================================================================================== // ================================================================================================= -#define DOCTEST_VERSION_MAJOR 1 -#define DOCTEST_VERSION_MINOR 2 +#define DOCTEST_VERSION_MAJOR 2 +#define DOCTEST_VERSION_MINOR 4 #define DOCTEST_VERSION_PATCH 9 -#define DOCTEST_VERSION_STR "1.2.9" + +// util we need here +#define DOCTEST_TOSTR_IMPL(x) #x +#define DOCTEST_TOSTR(x) DOCTEST_TOSTR_IMPL(x) + +#define DOCTEST_VERSION_STR \ + DOCTEST_TOSTR(DOCTEST_VERSION_MAJOR) "." \ + DOCTEST_TOSTR(DOCTEST_VERSION_MINOR) "." \ + DOCTEST_TOSTR(DOCTEST_VERSION_PATCH) #define DOCTEST_VERSION \ (DOCTEST_VERSION_MAJOR * 10000 + DOCTEST_VERSION_MINOR * 100 + DOCTEST_VERSION_PATCH) @@ -65,21 +68,29 @@ // ideas for the version stuff are taken from here: https://github.com/cxxstuff/cxx_detect +#ifdef _MSC_VER +#define DOCTEST_CPLUSPLUS _MSVC_LANG +#else +#define DOCTEST_CPLUSPLUS __cplusplus +#endif + #define DOCTEST_COMPILER(MAJOR, MINOR, PATCH) ((MAJOR)*10000000 + (MINOR)*100000 + (PATCH)) +// GCC/Clang and GCC/MSVC are mutually exclusive, but Clang/MSVC are not because of clang-cl... #if defined(_MSC_VER) && defined(_MSC_FULL_VER) #if _MSC_VER == _MSC_FULL_VER / 10000 #define DOCTEST_MSVC DOCTEST_COMPILER(_MSC_VER / 100, _MSC_VER % 100, _MSC_FULL_VER % 10000) -#else +#else // MSVC #define DOCTEST_MSVC \ DOCTEST_COMPILER(_MSC_VER / 100, (_MSC_FULL_VER / 100000) % 100, _MSC_FULL_VER % 100000) -#endif -#elif defined(__clang__) && defined(__clang_minor__) +#endif // MSVC +#endif // MSVC +#if defined(__clang__) && defined(__clang_minor__) #define DOCTEST_CLANG DOCTEST_COMPILER(__clang_major__, __clang_minor__, __clang_patchlevel__) #elif defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__) && \ !defined(__INTEL_COMPILER) #define DOCTEST_GCC DOCTEST_COMPILER(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) -#endif +#endif // GCC #ifndef DOCTEST_MSVC #define DOCTEST_MSVC 0 @@ -96,150 +107,136 @@ // ================================================================================================= #if DOCTEST_CLANG -#ifdef __has_warning -#define DOCTEST_CLANG_HAS_WARNING(x) __has_warning(x) -#endif // __has_warning -#ifdef __has_feature -#define DOCTEST_CLANG_HAS_FEATURE(x) __has_feature(x) -#endif // __has_feature #define DOCTEST_PRAGMA_TO_STR(x) _Pragma(#x) #define DOCTEST_CLANG_SUPPRESS_WARNING_PUSH _Pragma("clang diagnostic push") -#define DOCTEST_MSVC_SUPPRESS_WARNING_PUSH -#define DOCTEST_GCC_SUPPRESS_WARNING_PUSH #define DOCTEST_CLANG_SUPPRESS_WARNING(w) DOCTEST_PRAGMA_TO_STR(clang diagnostic ignored w) -#define DOCTEST_MSVC_SUPPRESS_WARNING(w) -#define DOCTEST_GCC_SUPPRESS_WARNING(w) #define DOCTEST_CLANG_SUPPRESS_WARNING_POP _Pragma("clang diagnostic pop") -#define DOCTEST_MSVC_SUPPRESS_WARNING_POP -#define DOCTEST_GCC_SUPPRESS_WARNING_POP #define DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH(w) \ DOCTEST_CLANG_SUPPRESS_WARNING_PUSH DOCTEST_CLANG_SUPPRESS_WARNING(w) -#define DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(w) -#define DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH(w) -#elif DOCTEST_GCC -#define DOCTEST_PRAGMA_TO_STR(x) _Pragma(#x) +#else // DOCTEST_CLANG #define DOCTEST_CLANG_SUPPRESS_WARNING_PUSH -#define DOCTEST_MSVC_SUPPRESS_WARNING_PUSH -#if DOCTEST_GCC >= DOCTEST_COMPILER(4, 7, 0) -#define DOCTEST_GCC_SUPPRESS_WARNING_PUSH _Pragma("GCC diagnostic push") -#else // GCC 4.7+ -#define DOCTEST_GCC_SUPPRESS_WARNING_PUSH -#endif // GCC 4.7+ #define DOCTEST_CLANG_SUPPRESS_WARNING(w) -#define DOCTEST_MSVC_SUPPRESS_WARNING(w) -#define DOCTEST_GCC_SUPPRESS_WARNING(w) DOCTEST_PRAGMA_TO_STR(GCC diagnostic ignored w) #define DOCTEST_CLANG_SUPPRESS_WARNING_POP -#define DOCTEST_MSVC_SUPPRESS_WARNING_POP -#if DOCTEST_GCC >= DOCTEST_COMPILER(4, 7, 0) -#define DOCTEST_GCC_SUPPRESS_WARNING_POP _Pragma("GCC diagnostic pop") -#else // GCC 4.7+ -#define DOCTEST_GCC_SUPPRESS_WARNING_POP -#endif // GCC 4.7+ #define DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH(w) -#define DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(w) +#endif // DOCTEST_CLANG + +#if DOCTEST_GCC +#define DOCTEST_PRAGMA_TO_STR(x) _Pragma(#x) +#define DOCTEST_GCC_SUPPRESS_WARNING_PUSH _Pragma("GCC diagnostic push") +#define DOCTEST_GCC_SUPPRESS_WARNING(w) DOCTEST_PRAGMA_TO_STR(GCC diagnostic ignored w) +#define DOCTEST_GCC_SUPPRESS_WARNING_POP _Pragma("GCC diagnostic pop") #define DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH(w) \ DOCTEST_GCC_SUPPRESS_WARNING_PUSH DOCTEST_GCC_SUPPRESS_WARNING(w) -#elif DOCTEST_MSVC -#define DOCTEST_PRAGMA_TO_STR(x) -#define DOCTEST_CLANG_SUPPRESS_WARNING_PUSH -#define DOCTEST_MSVC_SUPPRESS_WARNING_PUSH __pragma(warning(push)) +#else // DOCTEST_GCC #define DOCTEST_GCC_SUPPRESS_WARNING_PUSH -#define DOCTEST_CLANG_SUPPRESS_WARNING(w) -#define DOCTEST_MSVC_SUPPRESS_WARNING(w) __pragma(warning(disable : w)) #define DOCTEST_GCC_SUPPRESS_WARNING(w) -#define DOCTEST_CLANG_SUPPRESS_WARNING_POP -#define DOCTEST_MSVC_SUPPRESS_WARNING_POP __pragma(warning(pop)) #define DOCTEST_GCC_SUPPRESS_WARNING_POP -#define DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH(w) -#define DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(w) \ - DOCTEST_MSVC_SUPPRESS_WARNING_PUSH DOCTEST_MSVC_SUPPRESS_WARNING(w) #define DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH(w) -#endif // different compilers - warning suppression macros - -#ifndef DOCTEST_CLANG_HAS_WARNING -#define DOCTEST_CLANG_HAS_WARNING(x) 1 -#endif // DOCTEST_CLANG_HAS_WARNING +#endif // DOCTEST_GCC -#ifndef DOCTEST_CLANG_HAS_FEATURE -#define DOCTEST_CLANG_HAS_FEATURE(x) 0 -#endif // DOCTEST_CLANG_HAS_FEATURE +#if DOCTEST_MSVC +#define DOCTEST_MSVC_SUPPRESS_WARNING_PUSH __pragma(warning(push)) +#define DOCTEST_MSVC_SUPPRESS_WARNING(w) __pragma(warning(disable : w)) +#define DOCTEST_MSVC_SUPPRESS_WARNING_POP __pragma(warning(pop)) +#define DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(w) \ + DOCTEST_MSVC_SUPPRESS_WARNING_PUSH DOCTEST_MSVC_SUPPRESS_WARNING(w) +#else // DOCTEST_MSVC +#define DOCTEST_MSVC_SUPPRESS_WARNING_PUSH +#define DOCTEST_MSVC_SUPPRESS_WARNING(w) +#define DOCTEST_MSVC_SUPPRESS_WARNING_POP +#define DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(w) +#endif // DOCTEST_MSVC // ================================================================================================= // == COMPILER WARNINGS ============================================================================ // ================================================================================================= +// both the header and the implementation suppress all of these, +// so it only makes sense to aggregrate them like so +#define DOCTEST_SUPPRESS_COMMON_WARNINGS_PUSH \ + DOCTEST_CLANG_SUPPRESS_WARNING_PUSH \ + DOCTEST_CLANG_SUPPRESS_WARNING("-Wunknown-pragmas") \ + DOCTEST_CLANG_SUPPRESS_WARNING("-Wweak-vtables") \ + DOCTEST_CLANG_SUPPRESS_WARNING("-Wpadded") \ + DOCTEST_CLANG_SUPPRESS_WARNING("-Wmissing-prototypes") \ + DOCTEST_CLANG_SUPPRESS_WARNING("-Wc++98-compat") \ + DOCTEST_CLANG_SUPPRESS_WARNING("-Wc++98-compat-pedantic") \ + \ + DOCTEST_GCC_SUPPRESS_WARNING_PUSH \ + DOCTEST_GCC_SUPPRESS_WARNING("-Wunknown-pragmas") \ + DOCTEST_GCC_SUPPRESS_WARNING("-Wpragmas") \ + DOCTEST_GCC_SUPPRESS_WARNING("-Weffc++") \ + DOCTEST_GCC_SUPPRESS_WARNING("-Wstrict-overflow") \ + DOCTEST_GCC_SUPPRESS_WARNING("-Wstrict-aliasing") \ + DOCTEST_GCC_SUPPRESS_WARNING("-Wmissing-declarations") \ + DOCTEST_GCC_SUPPRESS_WARNING("-Wuseless-cast") \ + DOCTEST_GCC_SUPPRESS_WARNING("-Wnoexcept") \ + \ + DOCTEST_MSVC_SUPPRESS_WARNING_PUSH \ + /* these 4 also disabled globally via cmake: */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(4514) /* unreferenced inline function has been removed */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(4571) /* SEH related */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(4710) /* function not inlined */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(4711) /* function selected for inline expansion*/ \ + /* */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(4616) /* invalid compiler warning */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(4619) /* invalid compiler warning */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(4996) /* The compiler encountered a deprecated declaration */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(4706) /* assignment within conditional expression */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(4512) /* 'class' : assignment operator could not be generated */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(4127) /* conditional expression is constant */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(4820) /* padding */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(4625) /* copy constructor was implicitly deleted */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(4626) /* assignment operator was implicitly deleted */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(5027) /* move assignment operator implicitly deleted */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(5026) /* move constructor was implicitly deleted */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(4640) /* construction of local static object not thread-safe */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(5045) /* Spectre mitigation for memory load */ \ + /* static analysis */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(26439) /* Function may not throw. Declare it 'noexcept' */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(26495) /* Always initialize a member variable */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(26451) /* Arithmetic overflow ... */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(26444) /* Avoid unnamed objects with custom ctor and dtor... */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(26812) /* Prefer 'enum class' over 'enum' */ + +#define DOCTEST_SUPPRESS_COMMON_WARNINGS_POP \ + DOCTEST_CLANG_SUPPRESS_WARNING_POP \ + DOCTEST_GCC_SUPPRESS_WARNING_POP \ + DOCTEST_MSVC_SUPPRESS_WARNING_POP + +DOCTEST_SUPPRESS_COMMON_WARNINGS_PUSH + DOCTEST_CLANG_SUPPRESS_WARNING_PUSH -DOCTEST_CLANG_SUPPRESS_WARNING("-Wunknown-pragmas") DOCTEST_CLANG_SUPPRESS_WARNING("-Wnon-virtual-dtor") -DOCTEST_CLANG_SUPPRESS_WARNING("-Wweak-vtables") -DOCTEST_CLANG_SUPPRESS_WARNING("-Wpadded") DOCTEST_CLANG_SUPPRESS_WARNING("-Wdeprecated") -DOCTEST_CLANG_SUPPRESS_WARNING("-Wmissing-prototypes") -DOCTEST_CLANG_SUPPRESS_WARNING("-Wunused-local-typedef") -DOCTEST_CLANG_SUPPRESS_WARNING("-Wc++11-long-long") -#if DOCTEST_CLANG && DOCTEST_CLANG_HAS_WARNING("-Wzero-as-null-pointer-constant") -DOCTEST_CLANG_SUPPRESS_WARNING("-Wzero-as-null-pointer-constant") -#endif // clang - 0 as null DOCTEST_GCC_SUPPRESS_WARNING_PUSH -DOCTEST_GCC_SUPPRESS_WARNING("-Wunknown-pragmas") -DOCTEST_GCC_SUPPRESS_WARNING("-Wpragmas") -DOCTEST_GCC_SUPPRESS_WARNING("-Weffc++") -DOCTEST_GCC_SUPPRESS_WARNING("-Wstrict-overflow") -DOCTEST_GCC_SUPPRESS_WARNING("-Wstrict-aliasing") DOCTEST_GCC_SUPPRESS_WARNING("-Wctor-dtor-privacy") -DOCTEST_GCC_SUPPRESS_WARNING("-Wmissing-declarations") DOCTEST_GCC_SUPPRESS_WARNING("-Wnon-virtual-dtor") -DOCTEST_GCC_SUPPRESS_WARNING("-Winline") -DOCTEST_GCC_SUPPRESS_WARNING("-Wlong-long") -DOCTEST_GCC_SUPPRESS_WARNING("-Wzero-as-null-pointer-constant") -DOCTEST_GCC_SUPPRESS_WARNING("-Wunused-local-typedefs") -DOCTEST_GCC_SUPPRESS_WARNING("-Wuseless-cast") +DOCTEST_GCC_SUPPRESS_WARNING("-Wsign-promo") DOCTEST_MSVC_SUPPRESS_WARNING_PUSH -DOCTEST_MSVC_SUPPRESS_WARNING(4616) // invalid compiler warning -DOCTEST_MSVC_SUPPRESS_WARNING(4619) // invalid compiler warning -DOCTEST_MSVC_SUPPRESS_WARNING(4996) // The compiler encountered a deprecated declaration -DOCTEST_MSVC_SUPPRESS_WARNING(4706) // assignment within conditional expression -DOCTEST_MSVC_SUPPRESS_WARNING(4512) // 'class' : assignment operator could not be generated -DOCTEST_MSVC_SUPPRESS_WARNING(4127) // conditional expression is constant -DOCTEST_MSVC_SUPPRESS_WARNING(4820) // padding -DOCTEST_MSVC_SUPPRESS_WARNING(4625) // copy constructor was implicitly defined as deleted -DOCTEST_MSVC_SUPPRESS_WARNING(4626) // assignment operator was implicitly defined as deleted -DOCTEST_MSVC_SUPPRESS_WARNING(5027) // move assignment operator was implicitly defined as deleted -DOCTEST_MSVC_SUPPRESS_WARNING(5026) // move constructor was implicitly defined as deleted DOCTEST_MSVC_SUPPRESS_WARNING(4623) // default constructor was implicitly defined as deleted -DOCTEST_MSVC_SUPPRESS_WARNING(4640) // construction of local static object is not thread-safe - -// C4548 - expression before comma has no effect; expected expression with side - effect -// C4986 - exception specification does not match previous declaration -// C4350 - behavior change: 'member1' called instead of 'member2' -// C4668 - 'x' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' -// C4365 - conversion from 'int' to 'unsigned long', signed/unsigned mismatch -// C4774 - format string expected in argument 'x' is not a string literal -// C4820 - padding in structs - -// only 4 should be disabled globally: -// - C4514 # unreferenced inline function has been removed -// - C4571 # SEH related -// - C4710 # function not inlined -// - C4711 # function 'x' selected for automatic inline expansion #define DOCTEST_MAKE_STD_HEADERS_CLEAN_FROM_WARNINGS_ON_WALL_BEGIN \ DOCTEST_MSVC_SUPPRESS_WARNING_PUSH \ - DOCTEST_MSVC_SUPPRESS_WARNING(4548) \ - DOCTEST_MSVC_SUPPRESS_WARNING(4986) \ - DOCTEST_MSVC_SUPPRESS_WARNING(4350) \ - DOCTEST_MSVC_SUPPRESS_WARNING(4668) \ - DOCTEST_MSVC_SUPPRESS_WARNING(4365) \ - DOCTEST_MSVC_SUPPRESS_WARNING(4774) \ - DOCTEST_MSVC_SUPPRESS_WARNING(4820) \ - DOCTEST_MSVC_SUPPRESS_WARNING(4625) \ - DOCTEST_MSVC_SUPPRESS_WARNING(4626) \ - DOCTEST_MSVC_SUPPRESS_WARNING(5027) \ - DOCTEST_MSVC_SUPPRESS_WARNING(5026) \ - DOCTEST_MSVC_SUPPRESS_WARNING(4623) \ - DOCTEST_MSVC_SUPPRESS_WARNING(5039) + DOCTEST_MSVC_SUPPRESS_WARNING(4548) /* before comma no effect; expected side - effect */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(4265) /* virtual functions, but destructor is not virtual */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(4986) /* exception specification does not match previous */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(4350) /* 'member1' called instead of 'member2' */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(4668) /* not defined as a preprocessor macro */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(4365) /* signed/unsigned mismatch */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(4774) /* format string not a string literal */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(4820) /* padding */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(4625) /* copy constructor was implicitly deleted */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(4626) /* assignment operator was implicitly deleted */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(5027) /* move assignment operator implicitly deleted */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(5026) /* move constructor was implicitly deleted */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(4623) /* default constructor was implicitly deleted */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(5039) /* pointer to pot. throwing function passed to extern C */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(5045) /* Spectre mitigation for memory load */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(5105) /* macro producing 'defined' has undefined behavior */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(4738) /* storing float result in memory, loss of performance */ #define DOCTEST_MAKE_STD_HEADERS_CLEAN_FROM_WARNINGS_ON_WALL_END DOCTEST_MSVC_SUPPRESS_WARNING_POP @@ -247,155 +244,25 @@ DOCTEST_MSVC_SUPPRESS_WARNING(4640) // construction of local static object is no // == FEATURE DETECTION ============================================================================ // ================================================================================================= -#if __cplusplus >= 201103L -#ifndef DOCTEST_CONFIG_WITH_DELETED_FUNCTIONS -#define DOCTEST_CONFIG_WITH_DELETED_FUNCTIONS -#endif // DOCTEST_CONFIG_WITH_DELETED_FUNCTIONS -#ifndef DOCTEST_CONFIG_WITH_RVALUE_REFERENCES -#define DOCTEST_CONFIG_WITH_RVALUE_REFERENCES -#endif // DOCTEST_CONFIG_WITH_RVALUE_REFERENCES -#ifndef DOCTEST_CONFIG_WITH_NULLPTR -#define DOCTEST_CONFIG_WITH_NULLPTR -#endif // DOCTEST_CONFIG_WITH_NULLPTR -#ifndef DOCTEST_CONFIG_WITH_LONG_LONG -#define DOCTEST_CONFIG_WITH_LONG_LONG -#endif // DOCTEST_CONFIG_WITH_LONG_LONG -#ifndef DOCTEST_CONFIG_WITH_STATIC_ASSERT -#define DOCTEST_CONFIG_WITH_STATIC_ASSERT -#endif // DOCTEST_CONFIG_WITH_STATIC_ASSERT -#ifndef DOCTEST_CONFIG_WITH_VARIADIC_MACROS -#define DOCTEST_CONFIG_WITH_VARIADIC_MACROS -#endif // DOCTEST_CONFIG_WITH_VARIADIC_MACROS -#endif // __cplusplus >= 201103L - +// general compiler feature support table: https://en.cppreference.com/w/cpp/compiler_support // MSVC C++11 feature support table: https://msdn.microsoft.com/en-us/library/hh567368.aspx // GCC C++11 feature support table: https://gcc.gnu.org/projects/cxx-status.html // MSVC version table: -// MSVC++ 15.0 _MSC_VER == 1910 (Visual Studio 2017) -// MSVC++ 14.0 _MSC_VER == 1900 (Visual Studio 2015) -// MSVC++ 12.0 _MSC_VER == 1800 (Visual Studio 2013) -// MSVC++ 11.0 _MSC_VER == 1700 (Visual Studio 2012) -// MSVC++ 10.0 _MSC_VER == 1600 (Visual Studio 2010) -// MSVC++ 9.0 _MSC_VER == 1500 (Visual Studio 2008) -// MSVC++ 8.0 _MSC_VER == 1400 (Visual Studio 2005) - -// deleted functions - -#ifndef DOCTEST_CONFIG_WITH_DELETED_FUNCTIONS -#if DOCTEST_MSVC >= DOCTEST_COMPILER(18, 0, 0) -#define DOCTEST_CONFIG_WITH_DELETED_FUNCTIONS -#endif // MSVC -#if DOCTEST_CLANG && DOCTEST_CLANG_HAS_FEATURE(cxx_deleted_functions) -#define DOCTEST_CONFIG_WITH_DELETED_FUNCTIONS -#endif // clang -#if DOCTEST_GCC >= DOCTEST_COMPILER(4, 5, 0) && defined(__GXX_EXPERIMENTAL_CXX0X__) -#define DOCTEST_CONFIG_WITH_DELETED_FUNCTIONS -#endif // GCC -#endif // DOCTEST_CONFIG_WITH_DELETED_FUNCTIONS - -#if defined(DOCTEST_CONFIG_NO_DELETED_FUNCTIONS) && defined(DOCTEST_CONFIG_WITH_DELETED_FUNCTIONS) -#undef DOCTEST_CONFIG_WITH_DELETED_FUNCTIONS -#endif // DOCTEST_CONFIG_NO_DELETED_FUNCTIONS - -// rvalue references - -#ifndef DOCTEST_CONFIG_WITH_RVALUE_REFERENCES -#if DOCTEST_MSVC >= DOCTEST_COMPILER(16, 0, 0) -#define DOCTEST_CONFIG_WITH_RVALUE_REFERENCES -#endif // MSVC -#if DOCTEST_CLANG && DOCTEST_CLANG_HAS_FEATURE(cxx_rvalue_references) -#define DOCTEST_CONFIG_WITH_RVALUE_REFERENCES -#endif // clang -#if DOCTEST_GCC >= DOCTEST_COMPILER(4, 3, 0) && defined(__GXX_EXPERIMENTAL_CXX0X__) -#define DOCTEST_CONFIG_WITH_RVALUE_REFERENCES -#endif // GCC -#endif // DOCTEST_CONFIG_WITH_RVALUE_REFERENCES - -#if defined(DOCTEST_CONFIG_NO_RVALUE_REFERENCES) && defined(DOCTEST_CONFIG_WITH_RVALUE_REFERENCES) -#undef DOCTEST_CONFIG_WITH_RVALUE_REFERENCES -#endif // DOCTEST_CONFIG_NO_RVALUE_REFERENCES - -// nullptr - -#ifndef DOCTEST_CONFIG_WITH_NULLPTR -#if DOCTEST_CLANG && DOCTEST_CLANG_HAS_FEATURE(cxx_nullptr) -#define DOCTEST_CONFIG_WITH_NULLPTR -#endif // clang -#if DOCTEST_GCC >= DOCTEST_COMPILER(4, 6, 0) && defined(__GXX_EXPERIMENTAL_CXX0X__) -#define DOCTEST_CONFIG_WITH_NULLPTR -#endif // GCC -#if DOCTEST_MSVC >= DOCTEST_COMPILER(16, 0, 0) -#define DOCTEST_CONFIG_WITH_NULLPTR -#endif // MSVC -#endif // DOCTEST_CONFIG_WITH_NULLPTR - -#if defined(DOCTEST_CONFIG_NO_NULLPTR) && defined(DOCTEST_CONFIG_WITH_NULLPTR) -#undef DOCTEST_CONFIG_WITH_NULLPTR -#endif // DOCTEST_CONFIG_NO_NULLPTR - -// variadic macros - -#ifndef DOCTEST_CONFIG_WITH_VARIADIC_MACROS -#if DOCTEST_MSVC >= DOCTEST_COMPILER(14, 0, 0) && !defined(__EDGE__) -#define DOCTEST_CONFIG_WITH_VARIADIC_MACROS -#endif // MSVC -#if(DOCTEST_CLANG || DOCTEST_GCC >= DOCTEST_COMPILER(4, 1, 0)) && \ - defined(__GXX_EXPERIMENTAL_CXX0X__) -#define DOCTEST_CONFIG_WITH_VARIADIC_MACROS -#endif // GCC and clang -#endif // DOCTEST_CONFIG_WITH_VARIADIC_MACROS - -#if defined(DOCTEST_CONFIG_NO_VARIADIC_MACROS) && defined(DOCTEST_CONFIG_WITH_VARIADIC_MACROS) -#undef DOCTEST_CONFIG_WITH_VARIADIC_MACROS -#endif // DOCTEST_CONFIG_NO_VARIADIC_MACROS - -// long long - -#ifndef DOCTEST_CONFIG_WITH_LONG_LONG -#if DOCTEST_MSVC >= DOCTEST_COMPILER(14, 0, 0) -#define DOCTEST_CONFIG_WITH_LONG_LONG -#endif // MSVC -#if(DOCTEST_CLANG || DOCTEST_GCC >= DOCTEST_COMPILER(4, 5, 0)) && \ - defined(__GXX_EXPERIMENTAL_CXX0X__) -#define DOCTEST_CONFIG_WITH_LONG_LONG -#endif // GCC and clang -#endif // DOCTEST_CONFIG_WITH_LONG_LONG - -#if defined(DOCTEST_CONFIG_NO_LONG_LONG) && defined(DOCTEST_CONFIG_WITH_LONG_LONG) -#undef DOCTEST_CONFIG_WITH_LONG_LONG -#endif // DOCTEST_CONFIG_NO_LONG_LONG - -// static_assert - -#ifndef DOCTEST_CONFIG_WITH_STATIC_ASSERT -#if DOCTEST_CLANG && DOCTEST_CLANG_HAS_FEATURE(cxx_static_assert) -#define DOCTEST_CONFIG_WITH_STATIC_ASSERT -#endif // clang -#if DOCTEST_GCC >= DOCTEST_COMPILER(4, 3, 0) && defined(__GXX_EXPERIMENTAL_CXX0X__) -#define DOCTEST_CONFIG_WITH_STATIC_ASSERT -#endif // GCC -#if DOCTEST_MSVC >= DOCTEST_COMPILER(16, 0, 0) -#define DOCTEST_CONFIG_WITH_STATIC_ASSERT -#endif // MSVC -#endif // DOCTEST_CONFIG_WITH_STATIC_ASSERT - -#if defined(DOCTEST_CONFIG_NO_STATIC_ASSERT) && defined(DOCTEST_CONFIG_WITH_STATIC_ASSERT) -#undef DOCTEST_CONFIG_WITH_STATIC_ASSERT -#endif // DOCTEST_CONFIG_NO_STATIC_ASSERT - -// other stuff... - -#if defined(DOCTEST_CONFIG_WITH_RVALUE_REFERENCES) || defined(DOCTEST_CONFIG_WITH_LONG_LONG) || \ - defined(DOCTEST_CONFIG_WITH_DELETED_FUNCTIONS) || defined(DOCTEST_CONFIG_WITH_NULLPTR) || \ - defined(DOCTEST_CONFIG_WITH_VARIADIC_MACROS) || defined(DOCTEST_CONFIG_WITH_STATIC_ASSERT) -#define DOCTEST_NO_CPP11_COMPAT -#endif // c++11 stuff - -#if defined(DOCTEST_NO_CPP11_COMPAT) -DOCTEST_CLANG_SUPPRESS_WARNING("-Wc++98-compat") -DOCTEST_CLANG_SUPPRESS_WARNING("-Wc++98-compat-pedantic") -#endif // DOCTEST_NO_CPP11_COMPAT - +// https://en.wikipedia.org/wiki/Microsoft_Visual_C%2B%2B#Internal_version_numbering +// MSVC++ 14.3 (17) _MSC_VER == 1930 (Visual Studio 2022) +// MSVC++ 14.2 (16) _MSC_VER == 1920 (Visual Studio 2019) +// MSVC++ 14.1 (15) _MSC_VER == 1910 (Visual Studio 2017) +// MSVC++ 14.0 _MSC_VER == 1900 (Visual Studio 2015) +// MSVC++ 12.0 _MSC_VER == 1800 (Visual Studio 2013) +// MSVC++ 11.0 _MSC_VER == 1700 (Visual Studio 2012) +// MSVC++ 10.0 _MSC_VER == 1600 (Visual Studio 2010) +// MSVC++ 9.0 _MSC_VER == 1500 (Visual Studio 2008) +// MSVC++ 8.0 _MSC_VER == 1400 (Visual Studio 2005) + +// Universal Windows Platform support +#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) +#define DOCTEST_CONFIG_NO_WINDOWS_SEH +#endif // WINAPI_FAMILY #if DOCTEST_MSVC && !defined(DOCTEST_CONFIG_WINDOWS_SEH) #define DOCTEST_CONFIG_WINDOWS_SEH #endif // MSVC @@ -403,7 +270,8 @@ DOCTEST_CLANG_SUPPRESS_WARNING("-Wc++98-compat-pedantic") #undef DOCTEST_CONFIG_WINDOWS_SEH #endif // DOCTEST_CONFIG_NO_WINDOWS_SEH -#if !defined(_WIN32) && !defined(__QNX__) && !defined(DOCTEST_CONFIG_POSIX_SIGNALS) +#if !defined(_WIN32) && !defined(__QNX__) && !defined(DOCTEST_CONFIG_POSIX_SIGNALS) && \ + !defined(__EMSCRIPTEN__) && !defined(__wasi__) #define DOCTEST_CONFIG_POSIX_SIGNALS #endif // _WIN32 #if defined(DOCTEST_CONFIG_NO_POSIX_SIGNALS) && defined(DOCTEST_CONFIG_POSIX_SIGNALS) @@ -411,11 +279,10 @@ DOCTEST_CLANG_SUPPRESS_WARNING("-Wc++98-compat-pedantic") #endif // DOCTEST_CONFIG_NO_POSIX_SIGNALS #ifndef DOCTEST_CONFIG_NO_EXCEPTIONS -#if(DOCTEST_GCC || DOCTEST_CLANG) && !defined(__EXCEPTIONS) +#if !defined(__cpp_exceptions) && !defined(__EXCEPTIONS) && !defined(_CPPUNWIND) \ + || defined(__wasi__) #define DOCTEST_CONFIG_NO_EXCEPTIONS -#endif // clang and gcc -// in MSVC _HAS_EXCEPTIONS is defined in a header instead of as a project define -// so we can't do the automatic detection for MSVC without including some header +#endif // no exceptions #endif // DOCTEST_CONFIG_NO_EXCEPTIONS #ifdef DOCTEST_CONFIG_NO_EXCEPTIONS_BUT_WITH_ALL_ASSERTS @@ -428,11 +295,15 @@ DOCTEST_CLANG_SUPPRESS_WARNING("-Wc++98-compat-pedantic") #define DOCTEST_CONFIG_NO_TRY_CATCH_IN_ASSERTS #endif // DOCTEST_CONFIG_NO_EXCEPTIONS && !DOCTEST_CONFIG_NO_TRY_CATCH_IN_ASSERTS +#ifdef __wasi__ +#define DOCTEST_CONFIG_NO_MULTITHREADING +#endif + #if defined(DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN) && !defined(DOCTEST_CONFIG_IMPLEMENT) #define DOCTEST_CONFIG_IMPLEMENT #endif // DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN -#if defined _WIN32 || defined __CYGWIN__ +#if defined(_WIN32) || defined(__CYGWIN__) #if DOCTEST_MSVC #define DOCTEST_SYMBOL_EXPORT __declspec(dllexport) #define DOCTEST_SYMBOL_IMPORT __declspec(dllimport) @@ -455,24 +326,73 @@ DOCTEST_CLANG_SUPPRESS_WARNING("-Wc++98-compat-pedantic") #define DOCTEST_INTERFACE #endif // DOCTEST_CONFIG_IMPLEMENTATION_IN_DLL +// needed for extern template instantiations +// see https://github.com/fmtlib/fmt/issues/2228 +#if DOCTEST_MSVC +#define DOCTEST_INTERFACE_DECL +#define DOCTEST_INTERFACE_DEF DOCTEST_INTERFACE +#else // DOCTEST_MSVC +#define DOCTEST_INTERFACE_DECL DOCTEST_INTERFACE +#define DOCTEST_INTERFACE_DEF +#endif // DOCTEST_MSVC + +#define DOCTEST_EMPTY + #if DOCTEST_MSVC #define DOCTEST_NOINLINE __declspec(noinline) #define DOCTEST_UNUSED #define DOCTEST_ALIGNMENT(x) -#else // MSVC +#elif DOCTEST_CLANG && DOCTEST_CLANG < DOCTEST_COMPILER(3, 5, 0) +#define DOCTEST_NOINLINE +#define DOCTEST_UNUSED +#define DOCTEST_ALIGNMENT(x) +#else #define DOCTEST_NOINLINE __attribute__((noinline)) #define DOCTEST_UNUSED __attribute__((unused)) #define DOCTEST_ALIGNMENT(x) __attribute__((aligned(x))) -#endif // MSVC +#endif + +#ifndef DOCTEST_NORETURN +#if DOCTEST_MSVC && (DOCTEST_MSVC < DOCTEST_COMPILER(19, 0, 0)) +#define DOCTEST_NORETURN +#else // DOCTEST_MSVC +#define DOCTEST_NORETURN [[noreturn]] +#endif // DOCTEST_MSVC +#endif // DOCTEST_NORETURN -#ifndef DOCTEST_CONFIG_NUM_CAPTURES_ON_STACK -#define DOCTEST_CONFIG_NUM_CAPTURES_ON_STACK 5 -#endif // DOCTEST_CONFIG_NUM_CAPTURES_ON_STACK +#ifndef DOCTEST_NOEXCEPT +#if DOCTEST_MSVC && (DOCTEST_MSVC < DOCTEST_COMPILER(19, 0, 0)) +#define DOCTEST_NOEXCEPT +#else // DOCTEST_MSVC +#define DOCTEST_NOEXCEPT noexcept +#endif // DOCTEST_MSVC +#endif // DOCTEST_NOEXCEPT + +#ifndef DOCTEST_CONSTEXPR +#if DOCTEST_MSVC && (DOCTEST_MSVC < DOCTEST_COMPILER(19, 0, 0)) +#define DOCTEST_CONSTEXPR const +#define DOCTEST_CONSTEXPR_FUNC inline +#else // DOCTEST_MSVC +#define DOCTEST_CONSTEXPR constexpr +#define DOCTEST_CONSTEXPR_FUNC constexpr +#endif // DOCTEST_MSVC +#endif // DOCTEST_CONSTEXPR // ================================================================================================= // == FEATURE DETECTION END ======================================================================== // ================================================================================================= +#define DOCTEST_DECLARE_INTERFACE(name) \ + virtual ~name(); \ + name() = default; \ + name(const name&) = delete; \ + name(name&&) = delete; \ + name& operator=(const name&) = delete; \ + name& operator=(name&&) = delete; + +#define DOCTEST_DEFINE_INTERFACE(name) \ + name::~name() = default; + // internal macros for string concatenation and anonymous variable name generation #define DOCTEST_CAT_IMPL(s1, s2) s1##s2 #define DOCTEST_CAT(s1, s2) DOCTEST_CAT_IMPL(s1, s2) @@ -482,18 +402,6 @@ DOCTEST_CLANG_SUPPRESS_WARNING("-Wc++98-compat-pedantic") #define DOCTEST_ANONYMOUS(x) DOCTEST_CAT(x, __LINE__) #endif // __COUNTER__ -// macro for making a string out of an identifier -#ifdef DOCTEST_CONFIG_WITH_VARIADIC_MACROS -#define DOCTEST_TOSTR_IMPL(...) #__VA_ARGS__ -#define DOCTEST_TOSTR(...) DOCTEST_TOSTR_IMPL(__VA_ARGS__) -#else // DOCTEST_CONFIG_WITH_VARIADIC_MACROS -#define DOCTEST_TOSTR_IMPL(x) #x -#define DOCTEST_TOSTR(x) DOCTEST_TOSTR_IMPL(x) -#endif // DOCTEST_CONFIG_WITH_VARIADIC_MACROS - -// counts the number of elements in a C string -#define DOCTEST_COUNTOF(x) (sizeof(x) / sizeof(x[0])) - #ifndef DOCTEST_CONFIG_ASSERTION_PARAMETERS_BY_VALUE #define DOCTEST_REF_WRAP(x) x& #else // DOCTEST_CONFIG_ASSERTION_PARAMETERS_BY_VALUE @@ -501,140 +409,139 @@ DOCTEST_CLANG_SUPPRESS_WARNING("-Wc++98-compat-pedantic") #endif // DOCTEST_CONFIG_ASSERTION_PARAMETERS_BY_VALUE // not using __APPLE__ because... this is how Catch does it -#if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) +#ifdef __MAC_OS_X_VERSION_MIN_REQUIRED #define DOCTEST_PLATFORM_MAC #elif defined(__IPHONE_OS_VERSION_MIN_REQUIRED) #define DOCTEST_PLATFORM_IPHONE #elif defined(_WIN32) #define DOCTEST_PLATFORM_WINDOWS -#else +#elif defined(__wasi__) +#define DOCTEST_PLATFORM_WASI +#else // DOCTEST_PLATFORM #define DOCTEST_PLATFORM_LINUX -#endif +#endif // DOCTEST_PLATFORM + +namespace doctest { namespace detail { + static DOCTEST_CONSTEXPR int consume(const int*, int) noexcept { return 0; } +}} -#define DOCTEST_GLOBAL_NO_WARNINGS(var) \ - DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wglobal-constructors") static int var DOCTEST_UNUSED -#define DOCTEST_GLOBAL_NO_WARNINGS_END() DOCTEST_CLANG_SUPPRESS_WARNING_POP +#define DOCTEST_GLOBAL_NO_WARNINGS(var, ...) \ + DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wglobal-constructors") \ + static const int var = doctest::detail::consume(&var, __VA_ARGS__); \ + DOCTEST_CLANG_SUPPRESS_WARNING_POP +#ifndef DOCTEST_BREAK_INTO_DEBUGGER // should probably take a look at https://github.com/scottt/debugbreak -#ifdef DOCTEST_PLATFORM_MAC -#define DOCTEST_BREAK_INTO_DEBUGGER() __asm__("int $3\n" : :) +#ifdef DOCTEST_PLATFORM_LINUX +#if defined(__GNUC__) && (defined(__i386) || defined(__x86_64)) +// Break at the location of the failing check if possible +#define DOCTEST_BREAK_INTO_DEBUGGER() __asm__("int $3\n" : :) // NOLINT(hicpp-no-assembler) +#else +#include +#define DOCTEST_BREAK_INTO_DEBUGGER() raise(SIGTRAP) +#endif +#elif defined(DOCTEST_PLATFORM_MAC) +#if defined(__x86_64) || defined(__x86_64__) || defined(__amd64__) || defined(__i386) +#define DOCTEST_BREAK_INTO_DEBUGGER() __asm__("int $3\n" : :) // NOLINT(hicpp-no-assembler) +#elif defined(__ppc__) || defined(__ppc64__) +// https://www.cocoawithlove.com/2008/03/break-into-debugger.html +#define DOCTEST_BREAK_INTO_DEBUGGER() __asm__("li r0, 20\nsc\nnop\nli r0, 37\nli r4, 2\nsc\nnop\n": : : "memory","r0","r3","r4") // NOLINT(hicpp-no-assembler) +#else +#define DOCTEST_BREAK_INTO_DEBUGGER() __asm__("brk #0"); // NOLINT(hicpp-no-assembler) +#endif #elif DOCTEST_MSVC #define DOCTEST_BREAK_INTO_DEBUGGER() __debugbreak() #elif defined(__MINGW32__) +DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH("-Wredundant-decls") extern "C" __declspec(dllimport) void __stdcall DebugBreak(); +DOCTEST_GCC_SUPPRESS_WARNING_POP #define DOCTEST_BREAK_INTO_DEBUGGER() ::DebugBreak() #else // linux -#define DOCTEST_BREAK_INTO_DEBUGGER() ((void)0) +#define DOCTEST_BREAK_INTO_DEBUGGER() (static_cast(0)) #endif // linux +#endif // DOCTEST_BREAK_INTO_DEBUGGER + +// this is kept here for backwards compatibility since the config option was changed +#ifdef DOCTEST_CONFIG_USE_IOSFWD +#ifndef DOCTEST_CONFIG_USE_STD_HEADERS +#define DOCTEST_CONFIG_USE_STD_HEADERS +#endif +#endif // DOCTEST_CONFIG_USE_IOSFWD +// for clang - always include ciso646 (which drags some std stuff) because +// we want to check if we are using libc++ with the _LIBCPP_VERSION macro in +// which case we don't want to forward declare stuff from std - for reference: +// https://github.com/doctest/doctest/issues/126 +// https://github.com/doctest/doctest/issues/356 #if DOCTEST_CLANG -// to detect if libc++ is being used with clang (the _LIBCPP_VERSION identifier) #include +#ifdef _LIBCPP_VERSION +#ifndef DOCTEST_CONFIG_USE_STD_HEADERS +#define DOCTEST_CONFIG_USE_STD_HEADERS +#endif +#endif // _LIBCPP_VERSION #endif // clang -#ifdef _LIBCPP_VERSION -// not forward declaring ostream for libc++ because I had some problems (inline namespaces vs c++98) -// so the header is used - also it is very light and doesn't drag a ton of stuff -#include -#else // _LIBCPP_VERSION -#ifndef DOCTEST_CONFIG_USE_IOSFWD -namespace std -{ +#ifdef DOCTEST_CONFIG_USE_STD_HEADERS +#ifndef DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS +#define DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS +#endif // DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS +DOCTEST_MAKE_STD_HEADERS_CLEAN_FROM_WARNINGS_ON_WALL_BEGIN +#include +#include +#include +DOCTEST_MAKE_STD_HEADERS_CLEAN_FROM_WARNINGS_ON_WALL_END +#else // DOCTEST_CONFIG_USE_STD_HEADERS + +// Forward declaring 'X' in namespace std is not permitted by the C++ Standard. +DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4643) + +namespace std { // NOLINT(cert-dcl58-cpp) +typedef decltype(nullptr) nullptr_t; // NOLINT(modernize-use-using) +typedef decltype(sizeof(void*)) size_t; // NOLINT(modernize-use-using) template struct char_traits; template <> struct char_traits; template -class basic_ostream; -typedef basic_ostream > ostream; +class basic_ostream; // NOLINT(fuchsia-virtual-inheritance) +typedef basic_ostream> ostream; // NOLINT(modernize-use-using) +template +// NOLINTNEXTLINE +basic_ostream& operator<<(basic_ostream&, const char*); +template +class basic_istream; +typedef basic_istream> istream; // NOLINT(modernize-use-using) +template +class tuple; +#if DOCTEST_MSVC >= DOCTEST_COMPILER(19, 20, 0) +// see this issue on why this is needed: https://github.com/doctest/doctest/issues/183 +template +class allocator; +template +class basic_string; +using string = basic_string, allocator>; +#endif // VS 2019 } // namespace std -#else // DOCTEST_CONFIG_USE_IOSFWD -#include -#endif // DOCTEST_CONFIG_USE_IOSFWD -#endif // _LIBCPP_VERSION -// static assert macro - because of the c++98 support requires that the message is an -// identifier (no spaces and not a C string) - example without quotes: I_am_a_message -// taken from here: http://stackoverflow.com/a/1980156/3162383 -#ifdef DOCTEST_CONFIG_WITH_STATIC_ASSERT -#define DOCTEST_STATIC_ASSERT(expression, message) static_assert(expression, #message) -#else // DOCTEST_CONFIG_WITH_STATIC_ASSERT -#define DOCTEST_STATIC_ASSERT(expression, message) \ - struct DOCTEST_CAT(__static_assertion_at_line_, __LINE__) \ - { \ - doctest::detail::static_assert_impl::StaticAssertion((expression))> \ - DOCTEST_CAT(DOCTEST_CAT(DOCTEST_CAT(STATIC_ASSERTION_FAILED_AT_LINE_, __LINE__), \ - _), \ - message); \ - }; \ - typedef doctest::detail::static_assert_impl::StaticAssertionTest( \ - sizeof(DOCTEST_CAT(__static_assertion_at_line_, __LINE__)))> \ - DOCTEST_CAT(__static_assertion_test_at_line_, __LINE__) -#endif // DOCTEST_CONFIG_WITH_STATIC_ASSERT - -#ifdef DOCTEST_CONFIG_WITH_NULLPTR -#ifdef _LIBCPP_VERSION -#include -#else // _LIBCPP_VERSION -namespace std -{ -typedef decltype(nullptr) nullptr_t; -} -#endif // _LIBCPP_VERSION -#endif // DOCTEST_CONFIG_WITH_NULLPTR +DOCTEST_MSVC_SUPPRESS_WARNING_POP -#ifndef DOCTEST_CONFIG_DISABLE +#endif // DOCTEST_CONFIG_USE_STD_HEADERS #ifdef DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS #include #endif // DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS -namespace doctest -{ -namespace detail -{ - struct TestSuite - { - const char* m_test_suite; - const char* m_description; - bool m_skip; - bool m_may_fail; - bool m_should_fail; - int m_expected_failures; - double m_timeout; - - TestSuite& operator*(const char* in) { - m_test_suite = in; - // clear state - m_description = 0; - m_skip = false; - m_may_fail = false; - m_should_fail = false; - m_expected_failures = 0; - m_timeout = 0; - return *this; - } +namespace doctest { - template - TestSuite& operator*(const T& in) { - in.fill(*this); - return *this; - } - }; -} // namespace detail -} // namespace doctest +using std::size_t; -// in a separate namespace outside of doctest because the DOCTEST_TEST_SUITE macro -// introduces an anonymous namespace in which getCurrentTestSuite gets overridden -namespace doctest_detail_test_suite_ns -{ -DOCTEST_INTERFACE doctest::detail::TestSuite& getCurrentTestSuite(); -} // namespace doctest_detail_test_suite_ns +DOCTEST_INTERFACE extern bool is_running_in_test; -#endif // DOCTEST_CONFIG_DISABLE +#ifndef DOCTEST_CONFIG_STRING_SIZE_TYPE +#define DOCTEST_CONFIG_STRING_SIZE_TYPE unsigned +#endif -namespace doctest -{ // A 24 byte string class (can be as small as 17 for x64 and 13 for x86) that can hold strings with length // of up to 23 chars on the stack before going on the heap - the last byte of the buffer is used for: // - "is small" bit - the highest bit - if "0" then it is small - otherwise its "1" (128) @@ -647,7 +554,6 @@ namespace doctest // TODO: // - optimizations - like not deleting memory unnecessarily in operator= and etc. // - resize/reserve/clear -// - substr // - replace // - back/front // - iterator stuff @@ -657,700 +563,824 @@ namespace doctest // - relational operators as free functions - taking const char* as one of the params class DOCTEST_INTERFACE String { - static const unsigned len = 24; //!OCLINT avoid private static members - static const unsigned last = len - 1; //!OCLINT avoid private static members +public: + using size_type = DOCTEST_CONFIG_STRING_SIZE_TYPE; + +private: + static DOCTEST_CONSTEXPR size_type len = 24; //!OCLINT avoid private static members + static DOCTEST_CONSTEXPR size_type last = len - 1; //!OCLINT avoid private static members struct view // len should be more than sizeof(view) - because of the final byte for flags { char* ptr; - unsigned size; - unsigned capacity; + size_type size; + size_type capacity; }; union { - char buf[len]; + char buf[len]; // NOLINT(*-avoid-c-arrays) view data; }; - void copy(const String& other); + char* allocate(size_type sz); - void setOnHeap() { *reinterpret_cast(&buf[last]) = 128; } - void setLast(unsigned in = last) { buf[last] = char(in); } + bool isOnStack() const noexcept { return (buf[last] & 128) == 0; } + void setOnHeap() noexcept; + void setLast(size_type in = last) noexcept; + void setSize(size_type sz) noexcept; -public: - String() { - buf[0] = '\0'; - setLast(); - } + void copy(const String& other); - String(const char* in); +public: + static DOCTEST_CONSTEXPR size_type npos = static_cast(-1); - String(const String& other) { copy(other); } + String() noexcept; + ~String(); - ~String() { - if(!isOnStack()) - delete[] data.ptr; - } + // cppcheck-suppress noExplicitConstructor + String(const char* in); + String(const char* in, size_type in_size); - // GCC 4.9/5/6 report Wstrict-overflow when optimizations are ON and it got inlined in the vector class somewhere... - // see commit 574ef95f0cd379118be5011704664e4b5351f1e0 and build https://travis-ci.org/onqtam/doctest/builds/230671611 - DOCTEST_NOINLINE String& operator=(const String& other) { - if(this != &other) { - if(!isOnStack()) - delete[] data.ptr; + String(std::istream& in, size_type in_size); - copy(other); - } + String(const String& other); + String& operator=(const String& other); - return *this; - } String& operator+=(const String& other); - String operator+(const String& other) const { return String(*this) += other; } - -#ifdef DOCTEST_CONFIG_WITH_RVALUE_REFERENCES - String(String&& other); - String& operator=(String&& other); -#endif // DOCTEST_CONFIG_WITH_RVALUE_REFERENCES + String(String&& other) noexcept; + String& operator=(String&& other) noexcept; - bool isOnStack() const { return (buf[last] & 128) == 0; } - - char operator[](unsigned i) const { return const_cast(this)->operator[](i); } // NOLINT - char& operator[](unsigned i) { - if(isOnStack()) - return reinterpret_cast(buf)[i]; - return data.ptr[i]; - } + char operator[](size_type i) const; + char& operator[](size_type i); + // the only functions I'm willing to leave in the interface - available for inlining const char* c_str() const { return const_cast(this)->c_str(); } // NOLINT char* c_str() { - if(isOnStack()) + if (isOnStack()) { return reinterpret_cast(buf); + } return data.ptr; } - DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH("-Wmaybe-uninitialized") - unsigned size() const { - if(isOnStack()) - return last - (unsigned(buf[last]) & 31); // using "last" would work only if "len" is 32 - return data.size; - } - DOCTEST_GCC_SUPPRESS_WARNING_POP + size_type size() const; + size_type capacity() const; - unsigned capacity() const { - if(isOnStack()) - return len; - return data.capacity; - } + String substr(size_type pos, size_type cnt = npos) &&; + String substr(size_type pos, size_type cnt = npos) const &; + + size_type find(char ch, size_type pos = 0) const; + size_type rfind(char ch, size_type pos = npos) const; int compare(const char* other, bool no_case = false) const; int compare(const String& other, bool no_case = false) const; + +friend DOCTEST_INTERFACE std::ostream& operator<<(std::ostream& s, const String& in); }; -// clang-format off -inline bool operator==(const String& lhs, const String& rhs) { return lhs.compare(rhs) == 0; } -inline bool operator!=(const String& lhs, const String& rhs) { return lhs.compare(rhs) != 0; } -inline bool operator< (const String& lhs, const String& rhs) { return lhs.compare(rhs) < 0; } -inline bool operator> (const String& lhs, const String& rhs) { return lhs.compare(rhs) > 0; } -inline bool operator<=(const String& lhs, const String& rhs) { return (lhs != rhs) ? lhs.compare(rhs) < 0 : true; } -inline bool operator>=(const String& lhs, const String& rhs) { return (lhs != rhs) ? lhs.compare(rhs) > 0 : true; } -// clang-format on +DOCTEST_INTERFACE String operator+(const String& lhs, const String& rhs); -DOCTEST_INTERFACE std::ostream& operator<<(std::ostream& s, const String& in); +DOCTEST_INTERFACE bool operator==(const String& lhs, const String& rhs); +DOCTEST_INTERFACE bool operator!=(const String& lhs, const String& rhs); +DOCTEST_INTERFACE bool operator<(const String& lhs, const String& rhs); +DOCTEST_INTERFACE bool operator>(const String& lhs, const String& rhs); +DOCTEST_INTERFACE bool operator<=(const String& lhs, const String& rhs); +DOCTEST_INTERFACE bool operator>=(const String& lhs, const String& rhs); -namespace detail -{ -#ifndef DOCTEST_CONFIG_WITH_STATIC_ASSERT - namespace static_assert_impl - { - template - struct StaticAssertion; +class DOCTEST_INTERFACE Contains { +public: + explicit Contains(const String& string); - template <> - struct StaticAssertion - {}; + bool checkWith(const String& other) const; - template - struct StaticAssertionTest - {}; - } // namespace static_assert_impl -#endif // DOCTEST_CONFIG_WITH_STATIC_ASSERT + String string; +}; - template - struct enable_if - {}; +DOCTEST_INTERFACE String toString(const Contains& in); - template - struct enable_if - { typedef TYPE type; }; +DOCTEST_INTERFACE bool operator==(const String& lhs, const Contains& rhs); +DOCTEST_INTERFACE bool operator==(const Contains& lhs, const String& rhs); +DOCTEST_INTERFACE bool operator!=(const String& lhs, const Contains& rhs); +DOCTEST_INTERFACE bool operator!=(const Contains& lhs, const String& rhs); - template - struct deferred_false - // cppcheck-suppress unusedStructMember - { static const bool value = false; }; +namespace Color { + enum Enum + { + None = 0, + White, + Red, + Green, + Blue, + Cyan, + Yellow, + Grey, + + Bright = 0x10, + + BrightRed = Bright | Red, + BrightGreen = Bright | Green, + LightGrey = Bright | Grey, + BrightWhite = Bright | White + }; - // to silence the warning "-Wzero-as-null-pointer-constant" only for gcc 5 for the Approx template ctor - pragmas don't work for it... - inline void* getNull() { return 0; } + DOCTEST_INTERFACE std::ostream& operator<<(std::ostream& s, Color::Enum code); +} // namespace Color - namespace has_insertion_operator_impl +namespace assertType { + enum Enum { - typedef char no; - typedef char yes[2]; + // macro traits - struct any_t - { - template - // cppcheck-suppress noExplicitConstructor - any_t(const DOCTEST_REF_WRAP(T)); - }; + is_warn = 1, + is_check = 2 * is_warn, + is_require = 2 * is_check, - yes& testStreamable(std::ostream&); - no testStreamable(no); + is_normal = 2 * is_require, + is_throws = 2 * is_normal, + is_throws_as = 2 * is_throws, + is_throws_with = 2 * is_throws_as, + is_nothrow = 2 * is_throws_with, - no operator<<(const std::ostream&, const any_t&); + is_false = 2 * is_nothrow, + is_unary = 2 * is_false, // not checked anywhere - used just to distinguish the types - template - struct has_insertion_operator - { - static std::ostream& s; - static const DOCTEST_REF_WRAP(T) t; - static const bool value = sizeof(testStreamable(s << t)) == sizeof(yes); - }; - } // namespace has_insertion_operator_impl + is_eq = 2 * is_unary, + is_ne = 2 * is_eq, - template - struct has_insertion_operator : has_insertion_operator_impl::has_insertion_operator - {}; + is_lt = 2 * is_ne, + is_gt = 2 * is_lt, - DOCTEST_INTERFACE void my_memcpy(void* dest, const void* src, unsigned num); + is_ge = 2 * is_gt, + is_le = 2 * is_ge, - DOCTEST_INTERFACE std::ostream* createStream(); - DOCTEST_INTERFACE String getStreamResult(std::ostream*); - DOCTEST_INTERFACE void freeStream(std::ostream*); + // macro types - template - struct StringMakerBase - { - template - static String convert(const DOCTEST_REF_WRAP(T)) { - return "{?}"; - } - }; + DT_WARN = is_normal | is_warn, + DT_CHECK = is_normal | is_check, + DT_REQUIRE = is_normal | is_require, - template <> - struct StringMakerBase - { - template - static String convert(const DOCTEST_REF_WRAP(T) in) { - std::ostream* s = createStream(); - *s << in; - String result = getStreamResult(s); - freeStream(s); - return result; - } - }; + DT_WARN_FALSE = is_normal | is_false | is_warn, + DT_CHECK_FALSE = is_normal | is_false | is_check, + DT_REQUIRE_FALSE = is_normal | is_false | is_require, - DOCTEST_INTERFACE String rawMemoryToString(const void* object, unsigned size); + DT_WARN_THROWS = is_throws | is_warn, + DT_CHECK_THROWS = is_throws | is_check, + DT_REQUIRE_THROWS = is_throws | is_require, - template - String rawMemoryToString(const DOCTEST_REF_WRAP(T) object) { - return rawMemoryToString(&object, sizeof(object)); - } + DT_WARN_THROWS_AS = is_throws_as | is_warn, + DT_CHECK_THROWS_AS = is_throws_as | is_check, + DT_REQUIRE_THROWS_AS = is_throws_as | is_require, - class NullType - { - }; + DT_WARN_THROWS_WITH = is_throws_with | is_warn, + DT_CHECK_THROWS_WITH = is_throws_with | is_check, + DT_REQUIRE_THROWS_WITH = is_throws_with | is_require, - template - struct Typelist - { - typedef T Head; - typedef U Tail; - }; + DT_WARN_THROWS_WITH_AS = is_throws_with | is_throws_as | is_warn, + DT_CHECK_THROWS_WITH_AS = is_throws_with | is_throws_as | is_check, + DT_REQUIRE_THROWS_WITH_AS = is_throws_with | is_throws_as | is_require, - // type of recursive function - template - struct ForEachType; + DT_WARN_NOTHROW = is_nothrow | is_warn, + DT_CHECK_NOTHROW = is_nothrow | is_check, + DT_REQUIRE_NOTHROW = is_nothrow | is_require, - // Recursion rule - template - struct ForEachType, Callable> : public ForEachType - { - enum - { - value = 1 + ForEachType::value - }; + DT_WARN_EQ = is_normal | is_eq | is_warn, + DT_CHECK_EQ = is_normal | is_eq | is_check, + DT_REQUIRE_EQ = is_normal | is_eq | is_require, - explicit ForEachType(Callable& callable) - : ForEachType(callable) { -#if DOCTEST_MSVC && DOCTEST_MSVC < DOCTEST_COMPILER(19, 10, 0) - callable.operator()(); -#else // MSVC - callable.template operator()(); -#endif // MSVC - } - }; + DT_WARN_NE = is_normal | is_ne | is_warn, + DT_CHECK_NE = is_normal | is_ne | is_check, + DT_REQUIRE_NE = is_normal | is_ne | is_require, - // Recursion end - template - struct ForEachType, Callable> - { - public: - enum - { - value = 0 - }; + DT_WARN_GT = is_normal | is_gt | is_warn, + DT_CHECK_GT = is_normal | is_gt | is_check, + DT_REQUIRE_GT = is_normal | is_gt | is_require, - explicit ForEachType(Callable& callable) { -#if DOCTEST_MSVC && DOCTEST_MSVC < DOCTEST_COMPILER(19, 10, 0) - callable.operator()(); -#else // MSVC - callable.template operator()(); -#endif // MSVC - } - }; + DT_WARN_LT = is_normal | is_lt | is_warn, + DT_CHECK_LT = is_normal | is_lt | is_check, + DT_REQUIRE_LT = is_normal | is_lt | is_require, - template - const char* type_to_string() { - return "<>"; - } -} // namespace detail + DT_WARN_GE = is_normal | is_ge | is_warn, + DT_CHECK_GE = is_normal | is_ge | is_check, + DT_REQUIRE_GE = is_normal | is_ge | is_require, -template -struct Types -{ -private: - typedef typename Types::Result TailResult; + DT_WARN_LE = is_normal | is_le | is_warn, + DT_CHECK_LE = is_normal | is_le | is_check, + DT_REQUIRE_LE = is_normal | is_le | is_require, -public: - typedef detail::Typelist Result; -}; + DT_WARN_UNARY = is_normal | is_unary | is_warn, + DT_CHECK_UNARY = is_normal | is_unary | is_check, + DT_REQUIRE_UNARY = is_normal | is_unary | is_require, -template <> -struct Types<> -{ typedef detail::NullType Result; }; + DT_WARN_UNARY_FALSE = is_normal | is_false | is_unary | is_warn, + DT_CHECK_UNARY_FALSE = is_normal | is_false | is_unary | is_check, + DT_REQUIRE_UNARY_FALSE = is_normal | is_false | is_unary | is_require, + }; +} // namespace assertType -template -struct StringMaker : detail::StringMakerBase::value> -{}; +DOCTEST_INTERFACE const char* assertString(assertType::Enum at); +DOCTEST_INTERFACE const char* failureString(assertType::Enum at); +DOCTEST_INTERFACE const char* skipPathFromFilename(const char* file); -template -struct StringMaker +struct DOCTEST_INTERFACE TestCaseData { - template - static String convert(U* p) { - if(p) - return detail::rawMemoryToString(p); - return "NULL"; - } + String m_file; // the file in which the test was registered (using String - see #350) + unsigned m_line; // the line where the test was registered + const char* m_name; // name of the test case + const char* m_test_suite; // the test suite in which the test was added + const char* m_description; + bool m_skip; + bool m_no_breaks; + bool m_no_output; + bool m_may_fail; + bool m_should_fail; + int m_expected_failures; + double m_timeout; }; -template -struct StringMaker +struct DOCTEST_INTERFACE AssertData { - static String convert(R C::*p) { - if(p) - return detail::rawMemoryToString(p); - return "NULL"; - } + // common - for all asserts + const TestCaseData* m_test_case; + assertType::Enum m_at; + const char* m_file; + int m_line; + const char* m_expr; + bool m_failed; + + // exception-related - for all asserts + bool m_threw; + String m_exception; + + // for normal asserts + String m_decomp; + + // for specific exception-related asserts + bool m_threw_as; + const char* m_exception_type; + + class DOCTEST_INTERFACE StringContains { + private: + Contains content; + bool isContains; + + public: + StringContains(const String& str) : content(str), isContains(false) { } + StringContains(Contains cntn) : content(static_cast(cntn)), isContains(true) { } + + bool check(const String& str) { return isContains ? (content == str) : (content.string == str); } + + operator const String&() const { return content.string; } + + const char* c_str() const { return content.string.c_str(); } + } m_exception_string; + + AssertData(assertType::Enum at, const char* file, int line, const char* expr, + const char* exception_type, const StringContains& exception_string); }; -template -String toString(const DOCTEST_REF_WRAP(T) value) { - return StringMaker::convert(value); -} +struct DOCTEST_INTERFACE MessageData +{ + String m_string; + const char* m_file; + int m_line; + assertType::Enum m_severity; +}; -#ifdef DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING -DOCTEST_INTERFACE String toString(char* in); -DOCTEST_INTERFACE String toString(const char* in); -#endif // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING -DOCTEST_INTERFACE String toString(bool in); -DOCTEST_INTERFACE String toString(float in); -DOCTEST_INTERFACE String toString(double in); -DOCTEST_INTERFACE String toString(double long in); +struct DOCTEST_INTERFACE SubcaseSignature +{ + String m_name; + const char* m_file; + int m_line; -DOCTEST_INTERFACE String toString(char in); -DOCTEST_INTERFACE String toString(char signed in); -DOCTEST_INTERFACE String toString(char unsigned in); -DOCTEST_INTERFACE String toString(int short in); -DOCTEST_INTERFACE String toString(int short unsigned in); -DOCTEST_INTERFACE String toString(int in); -DOCTEST_INTERFACE String toString(int unsigned in); -DOCTEST_INTERFACE String toString(int long in); -DOCTEST_INTERFACE String toString(int long unsigned in); - -#ifdef DOCTEST_CONFIG_WITH_LONG_LONG -DOCTEST_INTERFACE String toString(int long long in); -DOCTEST_INTERFACE String toString(int long long unsigned in); -#endif // DOCTEST_CONFIG_WITH_LONG_LONG - -#ifdef DOCTEST_CONFIG_WITH_NULLPTR -DOCTEST_INTERFACE String toString(std::nullptr_t in); -#endif // DOCTEST_CONFIG_WITH_NULLPTR - -class DOCTEST_INTERFACE Approx + bool operator==(const SubcaseSignature& other) const; + bool operator<(const SubcaseSignature& other) const; +}; + +struct DOCTEST_INTERFACE IContextScope { -public: - explicit Approx(double value); + DOCTEST_DECLARE_INTERFACE(IContextScope) + virtual void stringify(std::ostream*) const = 0; +}; - Approx operator()(double value) const { - Approx approx(value); - approx.epsilon(m_epsilon); - approx.scale(m_scale); - return approx; - } +namespace detail { + struct DOCTEST_INTERFACE TestCase; +} // namespace detail +struct ContextOptions //!OCLINT too many fields +{ + std::ostream* cout = nullptr; // stdout stream + String binary_name; // the test binary name + + const detail::TestCase* currentTest = nullptr; + + // == parameters from the command line + String out; // output filename + String order_by; // how tests should be ordered + unsigned rand_seed; // the seed for rand ordering + + unsigned first; // the first (matching) test to be executed + unsigned last; // the last (matching) test to be executed + + int abort_after; // stop tests after this many failed assertions + int subcase_filter_levels; // apply the subcase filters for the first N levels + + bool success; // include successful assertions in output + bool case_sensitive; // if filtering should be case sensitive + bool exit; // if the program should be exited after the tests are ran/whatever + bool duration; // print the time duration of each test case + bool minimal; // minimal console output (only test failures) + bool quiet; // no console output + bool no_throw; // to skip exceptions-related assertion macros + bool no_exitcode; // if the framework should return 0 as the exitcode + bool no_run; // to not run the tests at all (can be done with an "*" exclude) + bool no_intro; // to not print the intro of the framework + bool no_version; // to not print the version of the framework + bool no_colors; // if output to the console should be colorized + bool force_colors; // forces the use of colors even when a tty cannot be detected + bool no_breaks; // to not break into the debugger + bool no_skip; // don't skip test cases which are marked to be skipped + bool gnu_file_line; // if line numbers should be surrounded with :x: and not (x): + bool no_path_in_filenames; // if the path to files should be removed from the output + bool no_line_numbers; // if source code line numbers should be omitted from the output + bool no_debug_output; // no output in the debug console when a debugger is attached + bool no_skipped_summary; // don't print "skipped" in the summary !!! UNDOCUMENTED !!! + bool no_time_in_output; // omit any time/timestamps from output !!! UNDOCUMENTED !!! + + bool help; // to print the help + bool version; // to print the version + bool count; // if only the count of matching tests is to be retrieved + bool list_test_cases; // to list all tests matching the filters + bool list_test_suites; // to list all suites matching the filters + bool list_reporters; // lists all registered reporters +}; + +namespace detail { + namespace types { #ifdef DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS - template - explicit Approx(const T& value, - typename detail::enable_if::value>::type* = - static_cast(detail::getNull())) { - *this = Approx(static_cast(value)); - } -#endif // DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS + using namespace std; +#else + template + struct enable_if { }; - // clang-format off - // overloads for double - the first one is necessary as it is in the implementation part of doctest - // as for the others - keeping them for potentially faster compile times - DOCTEST_INTERFACE friend bool operator==(double lhs, Approx const& rhs); - friend bool operator==(Approx const& lhs, double rhs) { return operator==(rhs, lhs); } - friend bool operator!=(double lhs, Approx const& rhs) { return !operator==(lhs, rhs); } - friend bool operator!=(Approx const& lhs, double rhs) { return !operator==(rhs, lhs); } - friend bool operator<=(double lhs, Approx const& rhs) { return lhs < rhs.m_value || lhs == rhs; } - friend bool operator<=(Approx const& lhs, double rhs) { return lhs.m_value < rhs || lhs == rhs; } - friend bool operator>=(double lhs, Approx const& rhs) { return lhs > rhs.m_value || lhs == rhs; } - friend bool operator>=(Approx const& lhs, double rhs) { return lhs.m_value > rhs || lhs == rhs; } - friend bool operator< (double lhs, Approx const& rhs) { return lhs < rhs.m_value && lhs != rhs; } - friend bool operator< (Approx const& lhs, double rhs) { return lhs.m_value < rhs && lhs != rhs; } - friend bool operator> (double lhs, Approx const& rhs) { return lhs > rhs.m_value && lhs != rhs; } - friend bool operator> (Approx const& lhs, double rhs) { return lhs.m_value > rhs && lhs != rhs; } + template + struct enable_if { using type = T; }; -#ifdef DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS -#define DOCTEST_APPROX_PREFIX \ - template friend typename detail::enable_if::value, bool>::type + struct true_type { static DOCTEST_CONSTEXPR bool value = true; }; + struct false_type { static DOCTEST_CONSTEXPR bool value = false; }; - DOCTEST_APPROX_PREFIX operator==(const T& lhs, const Approx& rhs) { return operator==(double(lhs), rhs); } - DOCTEST_APPROX_PREFIX operator==(const Approx& lhs, const T& rhs) { return operator==(rhs, lhs); } - DOCTEST_APPROX_PREFIX operator!=(const T& lhs, const Approx& rhs) { return !operator==(lhs, rhs); } - DOCTEST_APPROX_PREFIX operator!=(const Approx& lhs, const T& rhs) { return !operator==(rhs, lhs); } - DOCTEST_APPROX_PREFIX operator<=(const T& lhs, const Approx& rhs) { return double(lhs) < rhs.m_value || lhs == rhs; } - DOCTEST_APPROX_PREFIX operator<=(const Approx& lhs, const T& rhs) { return lhs.m_value < double(rhs) || lhs == rhs; } - DOCTEST_APPROX_PREFIX operator>=(const T& lhs, const Approx& rhs) { return double(lhs) > rhs.m_value || lhs == rhs; } - DOCTEST_APPROX_PREFIX operator>=(const Approx& lhs, const T& rhs) { return lhs.m_value > double(rhs) || lhs == rhs; } - DOCTEST_APPROX_PREFIX operator< (const T& lhs, const Approx& rhs) { return double(lhs) < rhs.m_value && lhs != rhs; } - DOCTEST_APPROX_PREFIX operator< (const Approx& lhs, const T& rhs) { return lhs.m_value < double(rhs) && lhs != rhs; } - DOCTEST_APPROX_PREFIX operator> (const T& lhs, const Approx& rhs) { return double(lhs) > rhs.m_value && lhs != rhs; } - DOCTEST_APPROX_PREFIX operator> (const Approx& lhs, const T& rhs) { return lhs.m_value > double(rhs) && lhs != rhs; } -#undef DOCTEST_APPROX_PREFIX -#endif // DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS + template struct remove_reference { using type = T; }; + template struct remove_reference { using type = T; }; + template struct remove_reference { using type = T; }; - // clang-format on + template struct is_rvalue_reference : false_type { }; + template struct is_rvalue_reference : true_type { }; - Approx& epsilon(double newEpsilon) { - m_epsilon = newEpsilon; - return *this; + template struct remove_const { using type = T; }; + template struct remove_const { using type = T; }; + + // Compiler intrinsics + template struct is_enum { static DOCTEST_CONSTEXPR bool value = __is_enum(T); }; + template struct underlying_type { using type = __underlying_type(T); }; + + template struct is_pointer : false_type { }; + template struct is_pointer : true_type { }; + + template struct is_array : false_type { }; + // NOLINTNEXTLINE(*-avoid-c-arrays) + template struct is_array : true_type { }; +#endif } -#ifdef DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS + // template - typename detail::enable_if::value, Approx&>::type epsilon( - const T& newEpsilon) { - m_epsilon = static_cast(newEpsilon); - return *this; + T&& declval(); + + template + DOCTEST_CONSTEXPR_FUNC T&& forward(typename types::remove_reference::type& t) DOCTEST_NOEXCEPT { + return static_cast(t); } -#endif // DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS - Approx& scale(double newScale) { - m_scale = newScale; - return *this; + template + DOCTEST_CONSTEXPR_FUNC T&& forward(typename types::remove_reference::type&& t) DOCTEST_NOEXCEPT { + return static_cast(t); } -#ifdef DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS template - typename detail::enable_if::value, Approx&>::type scale( - const T& newScale) { - m_scale = static_cast(newScale); - return *this; - } -#endif // DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS + struct deferred_false : types::false_type { }; - String toString() const; +// MSVS 2015 :( +#if defined(_MSC_VER) && _MSC_VER <= 1900 + template + struct has_global_insertion_operator : types::false_type { }; -private: - double m_epsilon; - double m_scale; - double m_value; -}; + template + struct has_global_insertion_operator(), declval()), void())> : types::true_type { }; -template <> -inline String toString(const DOCTEST_REF_WRAP(Approx) value) { - return value.toString(); -} + template + struct has_insertion_operator { static DOCTEST_CONSTEXPR bool value = has_global_insertion_operator::value; }; -#if !defined(DOCTEST_CONFIG_DISABLE) + template + struct insert_hack; -namespace detail -{ - // the function type this library works with - typedef void (*funcType)(); + template + struct insert_hack { + static void insert(std::ostream& os, const T& t) { ::operator<<(os, t); } + }; - namespace assertType - { - enum Enum - { - // macro traits + template + struct insert_hack { + static void insert(std::ostream& os, const T& t) { operator<<(os, t); } + }; - is_warn = 1, - is_check = 2, - is_require = 4, + template + using insert_hack_t = insert_hack::value>; +#else + template + struct has_insertion_operator : types::false_type { }; +#endif + +template +struct has_insertion_operator(), declval()), void())> : types::true_type { }; + + DOCTEST_INTERFACE std::ostream* tlssPush(); + DOCTEST_INTERFACE String tlssPop(); + + template + struct StringMakerBase { + template + static String convert(const DOCTEST_REF_WRAP(T)) { +#ifdef DOCTEST_CONFIG_REQUIRE_STRINGIFICATION_FOR_ALL_USED_TYPES + static_assert(deferred_false::value, "No stringification detected for type T. See string conversion manual"); +#endif + return "{?}"; + } + }; - is_throws = 8, - is_throws_as = 16, - is_nothrow = 32, + template + struct filldata; - is_fast = 64, // not checked anywhere - used just to distinguish the types - is_false = 128, - is_unary = 256, + template + void filloss(std::ostream* stream, const T& in) { + filldata::fill(stream, in); + } - is_eq = 512, - is_ne = 1024, + template + void filloss(std::ostream* stream, const T (&in)[N]) { // NOLINT(*-avoid-c-arrays) + // T[N], T(&)[N], T(&&)[N] have same behaviour. + // Hence remove reference. + filloss::type>(stream, in); + } - is_lt = 2048, - is_gt = 4096, + template + String toStream(const T& in) { + std::ostream* stream = tlssPush(); + filloss(stream, in); + return tlssPop(); + } - is_ge = 8192, - is_le = 16384, + template <> + struct StringMakerBase { + template + static String convert(const DOCTEST_REF_WRAP(T) in) { + return toStream(in); + } + }; +} // namespace detail - // macro types +template +struct StringMaker : public detail::StringMakerBase< + detail::has_insertion_operator::value || detail::types::is_pointer::value || detail::types::is_array::value> +{}; - DT_WARN = is_warn, - DT_CHECK = is_check, - DT_REQUIRE = is_require, +#ifndef DOCTEST_STRINGIFY +#ifdef DOCTEST_CONFIG_DOUBLE_STRINGIFY +#define DOCTEST_STRINGIFY(...) toString(toString(__VA_ARGS__)) +#else +#define DOCTEST_STRINGIFY(...) toString(__VA_ARGS__) +#endif +#endif - DT_WARN_FALSE = is_false | is_warn, - DT_CHECK_FALSE = is_false | is_check, - DT_REQUIRE_FALSE = is_false | is_require, +template +String toString() { +#if DOCTEST_MSVC >= 0 && DOCTEST_CLANG == 0 && DOCTEST_GCC == 0 + String ret = __FUNCSIG__; // class doctest::String __cdecl doctest::toString(void) + String::size_type beginPos = ret.find('<'); + return ret.substr(beginPos + 1, ret.size() - beginPos - static_cast(sizeof(">(void)"))); +#else + String ret = __PRETTY_FUNCTION__; // doctest::String toString() [with T = TYPE] + String::size_type begin = ret.find('=') + 2; + return ret.substr(begin, ret.size() - begin - 1); +#endif +} - DT_WARN_THROWS = is_throws | is_warn, - DT_CHECK_THROWS = is_throws | is_check, - DT_REQUIRE_THROWS = is_throws | is_require, +template ::value, bool>::type = true> +String toString(const DOCTEST_REF_WRAP(T) value) { + return StringMaker::convert(value); +} - DT_WARN_THROWS_AS = is_throws_as | is_warn, - DT_CHECK_THROWS_AS = is_throws_as | is_check, - DT_REQUIRE_THROWS_AS = is_throws_as | is_require, +#ifdef DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING +DOCTEST_INTERFACE String toString(const char* in); +#endif // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING - DT_WARN_NOTHROW = is_nothrow | is_warn, - DT_CHECK_NOTHROW = is_nothrow | is_check, - DT_REQUIRE_NOTHROW = is_nothrow | is_require, +#if DOCTEST_MSVC >= DOCTEST_COMPILER(19, 20, 0) +// see this issue on why this is needed: https://github.com/doctest/doctest/issues/183 +DOCTEST_INTERFACE String toString(const std::string& in); +#endif // VS 2019 - DT_WARN_EQ = is_eq | is_warn, - DT_CHECK_EQ = is_eq | is_check, - DT_REQUIRE_EQ = is_eq | is_require, +DOCTEST_INTERFACE String toString(String in); - DT_WARN_NE = is_ne | is_warn, - DT_CHECK_NE = is_ne | is_check, - DT_REQUIRE_NE = is_ne | is_require, +DOCTEST_INTERFACE String toString(std::nullptr_t); - DT_WARN_GT = is_gt | is_warn, - DT_CHECK_GT = is_gt | is_check, - DT_REQUIRE_GT = is_gt | is_require, +DOCTEST_INTERFACE String toString(bool in); - DT_WARN_LT = is_lt | is_warn, - DT_CHECK_LT = is_lt | is_check, - DT_REQUIRE_LT = is_lt | is_require, +DOCTEST_INTERFACE String toString(float in); +DOCTEST_INTERFACE String toString(double in); +DOCTEST_INTERFACE String toString(double long in); - DT_WARN_GE = is_ge | is_warn, - DT_CHECK_GE = is_ge | is_check, - DT_REQUIRE_GE = is_ge | is_require, +DOCTEST_INTERFACE String toString(char in); +DOCTEST_INTERFACE String toString(char signed in); +DOCTEST_INTERFACE String toString(char unsigned in); +DOCTEST_INTERFACE String toString(short in); +DOCTEST_INTERFACE String toString(short unsigned in); +DOCTEST_INTERFACE String toString(signed in); +DOCTEST_INTERFACE String toString(unsigned in); +DOCTEST_INTERFACE String toString(long in); +DOCTEST_INTERFACE String toString(long unsigned in); +DOCTEST_INTERFACE String toString(long long in); +DOCTEST_INTERFACE String toString(long long unsigned in); + +template ::value, bool>::type = true> +String toString(const DOCTEST_REF_WRAP(T) value) { + using UT = typename detail::types::underlying_type::type; + return (DOCTEST_STRINGIFY(static_cast(value))); +} - DT_WARN_LE = is_le | is_warn, - DT_CHECK_LE = is_le | is_check, - DT_REQUIRE_LE = is_le | is_require, +namespace detail { + template + struct filldata + { + static void fill(std::ostream* stream, const T& in) { +#if defined(_MSC_VER) && _MSC_VER <= 1900 + insert_hack_t::insert(*stream, in); +#else + operator<<(*stream, in); +#endif + } + }; - DT_WARN_UNARY = is_unary | is_warn, - DT_CHECK_UNARY = is_unary | is_check, - DT_REQUIRE_UNARY = is_unary | is_require, +DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4866) +// NOLINTBEGIN(*-avoid-c-arrays) + template + struct filldata { + static void fill(std::ostream* stream, const T(&in)[N]) { + *stream << "["; + for (size_t i = 0; i < N; i++) { + if (i != 0) { *stream << ", "; } + *stream << (DOCTEST_STRINGIFY(in[i])); + } + *stream << "]"; + } + }; +// NOLINTEND(*-avoid-c-arrays) +DOCTEST_MSVC_SUPPRESS_WARNING_POP - DT_WARN_UNARY_FALSE = is_false | is_unary | is_warn, - DT_CHECK_UNARY_FALSE = is_false | is_unary | is_check, - DT_REQUIRE_UNARY_FALSE = is_false | is_unary | is_require, + // Specialized since we don't want the terminating null byte! +// NOLINTBEGIN(*-avoid-c-arrays) + template + struct filldata { + static void fill(std::ostream* stream, const char (&in)[N]) { + *stream << String(in, in[N - 1] ? N : N - 1); + } // NOLINT(clang-analyzer-cplusplus.NewDeleteLeaks) + }; +// NOLINTEND(*-avoid-c-arrays) - DT_FAST_WARN_EQ = is_fast | is_eq | is_warn, - DT_FAST_CHECK_EQ = is_fast | is_eq | is_check, - DT_FAST_REQUIRE_EQ = is_fast | is_eq | is_require, + template <> + struct filldata { + static void fill(std::ostream* stream, const void* in); + }; - DT_FAST_WARN_NE = is_fast | is_ne | is_warn, - DT_FAST_CHECK_NE = is_fast | is_ne | is_check, - DT_FAST_REQUIRE_NE = is_fast | is_ne | is_require, + template + struct filldata { + static void fill(std::ostream* stream, const T* in) { + filldata::fill(stream, in); + } + }; +} - DT_FAST_WARN_GT = is_fast | is_gt | is_warn, - DT_FAST_CHECK_GT = is_fast | is_gt | is_check, - DT_FAST_REQUIRE_GT = is_fast | is_gt | is_require, +struct DOCTEST_INTERFACE Approx +{ + Approx(double value); - DT_FAST_WARN_LT = is_fast | is_lt | is_warn, - DT_FAST_CHECK_LT = is_fast | is_lt | is_check, - DT_FAST_REQUIRE_LT = is_fast | is_lt | is_require, + Approx operator()(double value) const; - DT_FAST_WARN_GE = is_fast | is_ge | is_warn, - DT_FAST_CHECK_GE = is_fast | is_ge | is_check, - DT_FAST_REQUIRE_GE = is_fast | is_ge | is_require, +#ifdef DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS + template + explicit Approx(const T& value, + typename detail::types::enable_if::value>::type* = + static_cast(nullptr)) { + *this = static_cast(value); + } +#endif // DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS - DT_FAST_WARN_LE = is_fast | is_le | is_warn, - DT_FAST_CHECK_LE = is_fast | is_le | is_check, - DT_FAST_REQUIRE_LE = is_fast | is_le | is_require, + Approx& epsilon(double newEpsilon); - DT_FAST_WARN_UNARY = is_fast | is_unary | is_warn, - DT_FAST_CHECK_UNARY = is_fast | is_unary | is_check, - DT_FAST_REQUIRE_UNARY = is_fast | is_unary | is_require, +#ifdef DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS + template + typename std::enable_if::value, Approx&>::type epsilon( + const T& newEpsilon) { + m_epsilon = static_cast(newEpsilon); + return *this; + } +#endif // DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS - DT_FAST_WARN_UNARY_FALSE = is_fast | is_false | is_unary | is_warn, - DT_FAST_CHECK_UNARY_FALSE = is_fast | is_false | is_unary | is_check, - DT_FAST_REQUIRE_UNARY_FALSE = is_fast | is_false | is_unary | is_require - }; - } // namespace assertType + Approx& scale(double newScale); - DOCTEST_INTERFACE const char* assertString(assertType::Enum val); +#ifdef DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS + template + typename std::enable_if::value, Approx&>::type scale( + const T& newScale) { + m_scale = static_cast(newScale); + return *this; + } +#endif // DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS // clang-format off - template struct decay_array { typedef T type; }; - template struct decay_array { typedef T* type; }; - template struct decay_array { typedef T* type; }; + DOCTEST_INTERFACE friend bool operator==(double lhs, const Approx & rhs); + DOCTEST_INTERFACE friend bool operator==(const Approx & lhs, double rhs); + DOCTEST_INTERFACE friend bool operator!=(double lhs, const Approx & rhs); + DOCTEST_INTERFACE friend bool operator!=(const Approx & lhs, double rhs); + DOCTEST_INTERFACE friend bool operator<=(double lhs, const Approx & rhs); + DOCTEST_INTERFACE friend bool operator<=(const Approx & lhs, double rhs); + DOCTEST_INTERFACE friend bool operator>=(double lhs, const Approx & rhs); + DOCTEST_INTERFACE friend bool operator>=(const Approx & lhs, double rhs); + DOCTEST_INTERFACE friend bool operator< (double lhs, const Approx & rhs); + DOCTEST_INTERFACE friend bool operator< (const Approx & lhs, double rhs); + DOCTEST_INTERFACE friend bool operator> (double lhs, const Approx & rhs); + DOCTEST_INTERFACE friend bool operator> (const Approx & lhs, double rhs); - template struct not_char_pointer { enum { value = 1 }; }; - template<> struct not_char_pointer { enum { value = 0 }; }; - template<> struct not_char_pointer { enum { value = 0 }; }; +#ifdef DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS +#define DOCTEST_APPROX_PREFIX \ + template friend typename std::enable_if::value, bool>::type + + DOCTEST_APPROX_PREFIX operator==(const T& lhs, const Approx& rhs) { return operator==(static_cast(lhs), rhs); } + DOCTEST_APPROX_PREFIX operator==(const Approx& lhs, const T& rhs) { return operator==(rhs, lhs); } + DOCTEST_APPROX_PREFIX operator!=(const T& lhs, const Approx& rhs) { return !operator==(lhs, rhs); } + DOCTEST_APPROX_PREFIX operator!=(const Approx& lhs, const T& rhs) { return !operator==(rhs, lhs); } + DOCTEST_APPROX_PREFIX operator<=(const T& lhs, const Approx& rhs) { return static_cast(lhs) < rhs.m_value || lhs == rhs; } + DOCTEST_APPROX_PREFIX operator<=(const Approx& lhs, const T& rhs) { return lhs.m_value < static_cast(rhs) || lhs == rhs; } + DOCTEST_APPROX_PREFIX operator>=(const T& lhs, const Approx& rhs) { return static_cast(lhs) > rhs.m_value || lhs == rhs; } + DOCTEST_APPROX_PREFIX operator>=(const Approx& lhs, const T& rhs) { return lhs.m_value > static_cast(rhs) || lhs == rhs; } + DOCTEST_APPROX_PREFIX operator< (const T& lhs, const Approx& rhs) { return static_cast(lhs) < rhs.m_value && lhs != rhs; } + DOCTEST_APPROX_PREFIX operator< (const Approx& lhs, const T& rhs) { return lhs.m_value < static_cast(rhs) && lhs != rhs; } + DOCTEST_APPROX_PREFIX operator> (const T& lhs, const Approx& rhs) { return static_cast(lhs) > rhs.m_value && lhs != rhs; } + DOCTEST_APPROX_PREFIX operator> (const Approx& lhs, const T& rhs) { return lhs.m_value > static_cast(rhs) && lhs != rhs; } +#undef DOCTEST_APPROX_PREFIX +#endif // DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS - template struct can_use_op : not_char_pointer::type> {}; // clang-format on - struct TestFailureException - { - }; + double m_epsilon; + double m_scale; + double m_value; +}; - DOCTEST_INTERFACE bool checkIfShouldThrow(assertType::Enum at); - DOCTEST_INTERFACE void fastAssertThrowIfFlagSet(int flags); +DOCTEST_INTERFACE String toString(const Approx& in); - struct TestAccessibleContextState - { - bool no_throw; // to skip exceptions-related assertion macros - bool success; // include successful assertions in output - }; +DOCTEST_INTERFACE const ContextOptions* getContextOptions(); - struct ContextState; +template +struct DOCTEST_INTERFACE_DECL IsNaN +{ + F value; bool flipped; + IsNaN(F f, bool flip = false) : value(f), flipped(flip) { } + IsNaN operator!() const { return { value, !flipped }; } + operator bool() const; +}; +#ifndef __MINGW32__ +extern template struct DOCTEST_INTERFACE_DECL IsNaN; +extern template struct DOCTEST_INTERFACE_DECL IsNaN; +extern template struct DOCTEST_INTERFACE_DECL IsNaN; +#endif +DOCTEST_INTERFACE String toString(IsNaN in); +DOCTEST_INTERFACE String toString(IsNaN in); +DOCTEST_INTERFACE String toString(IsNaN in); - DOCTEST_INTERFACE TestAccessibleContextState* getTestsContextState(); +#ifndef DOCTEST_CONFIG_DISABLE - struct DOCTEST_INTERFACE SubcaseSignature - { - const char* m_name; - const char* m_file; - int m_line; +namespace detail { + // clang-format off +#ifdef DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING + template struct decay_array { using type = T; }; + template struct decay_array { using type = T*; }; + template struct decay_array { using type = T*; }; + + template struct not_char_pointer { static DOCTEST_CONSTEXPR value = 1; }; + template<> struct not_char_pointer { static DOCTEST_CONSTEXPR value = 0; }; + template<> struct not_char_pointer { static DOCTEST_CONSTEXPR value = 0; }; - SubcaseSignature(const char* name, const char* file, int line) - : m_name(name) - , m_file(file) - , m_line(line) {} + template struct can_use_op : public not_char_pointer::type> {}; +#endif // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING + // clang-format on - bool operator<(const SubcaseSignature& other) const; + struct DOCTEST_INTERFACE TestFailureException + { }; - // cppcheck-suppress copyCtorAndEqOperator + DOCTEST_INTERFACE bool checkIfShouldThrow(assertType::Enum at); + +#ifndef DOCTEST_CONFIG_NO_EXCEPTIONS + DOCTEST_NORETURN +#endif // DOCTEST_CONFIG_NO_EXCEPTIONS + DOCTEST_INTERFACE void throwException(); + struct DOCTEST_INTERFACE Subcase { SubcaseSignature m_signature; - bool m_entered; + bool m_entered = false; - Subcase(const char* name, const char* file, int line); - Subcase(const Subcase& other); + Subcase(const String& name, const char* file, int line); + Subcase(const Subcase&) = delete; + Subcase(Subcase&&) = delete; + Subcase& operator=(const Subcase&) = delete; + Subcase& operator=(Subcase&&) = delete; ~Subcase(); - operator bool() const { return m_entered; } + operator bool() const; + + private: + bool checkFilters(); }; template String stringifyBinaryExpr(const DOCTEST_REF_WRAP(L) lhs, const char* op, const DOCTEST_REF_WRAP(R) rhs) { - return toString(lhs) + op + toString(rhs); + return (DOCTEST_STRINGIFY(lhs)) + op + (DOCTEST_STRINGIFY(rhs)); } - struct DOCTEST_INTERFACE Result - { - bool m_passed; - String m_decomposition; - - ~Result(); - - DOCTEST_NOINLINE Result(bool passed = false, const String& decomposition = String()) - : m_passed(passed) - , m_decomposition(decomposition) {} +#if DOCTEST_CLANG && DOCTEST_CLANG < DOCTEST_COMPILER(3, 6, 0) +DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wunused-comparison") +#endif - DOCTEST_NOINLINE Result(const Result& other) - : m_passed(other.m_passed) - , m_decomposition(other.m_decomposition) {} +// This will check if there is any way it could find a operator like member or friend and uses it. +// If not it doesn't find the operator or if the operator at global scope is defined after +// this template, the template won't be instantiated due to SFINAE. Once the template is not +// instantiated it can look for global operator using normal conversions. +#define SFINAE_OP(ret,op) decltype((void)(doctest::detail::declval() op doctest::detail::declval()),ret{}) - Result& operator=(const Result& other); +#define DOCTEST_DO_BINARY_EXPRESSION_COMPARISON(op, op_str, op_macro) \ + template \ + DOCTEST_NOINLINE SFINAE_OP(Result,op) operator op(R&& rhs) { \ + bool res = op_macro(doctest::detail::forward(lhs), doctest::detail::forward(rhs)); \ + if(m_at & assertType::is_false) \ + res = !res; \ + if(!res || doctest::getContextOptions()->success) \ + return Result(res, stringifyBinaryExpr(lhs, op_str, rhs)); \ + return Result(res); \ + } - operator bool() { return !m_passed; } + // more checks could be added - like in Catch: + // https://github.com/catchorg/Catch2/pull/1480/files + // https://github.com/catchorg/Catch2/pull/1481/files +#define DOCTEST_FORBIT_EXPRESSION(rt, op) \ + template \ + rt& operator op(const R&) { \ + static_assert(deferred_false::value, \ + "Expression Too Complex Please Rewrite As Binary Comparison!"); \ + return *this; \ + } - // clang-format off - // forbidding some expressions based on this table: http://en.cppreference.com/w/cpp/language/operator_precedence - template Result& operator& (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return *this; } - template Result& operator^ (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return *this; } - template Result& operator| (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return *this; } - template Result& operator&& (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return *this; } - template Result& operator|| (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return *this; } - template Result& operator== (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return *this; } - template Result& operator!= (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return *this; } - template Result& operator< (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return *this; } - template Result& operator> (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return *this; } - template Result& operator<= (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return *this; } - template Result& operator>= (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return *this; } - template Result& operator= (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return *this; } - template Result& operator+= (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return *this; } - template Result& operator-= (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return *this; } - template Result& operator*= (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return *this; } - template Result& operator/= (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return *this; } - template Result& operator%= (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return *this; } - template Result& operator<<=(const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return *this; } - template Result& operator>>=(const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return *this; } - template Result& operator&= (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return *this; } - template Result& operator^= (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return *this; } - template Result& operator|= (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return *this; } - // clang-format on + struct DOCTEST_INTERFACE Result // NOLINT(*-member-init) + { + bool m_passed; + String m_decomp; + + Result() = default; // TODO: Why do we need this? (To remove NOLINT) + Result(bool passed, const String& decomposition = String()); + + // forbidding some expressions based on this table: https://en.cppreference.com/w/cpp/language/operator_precedence + DOCTEST_FORBIT_EXPRESSION(Result, &) + DOCTEST_FORBIT_EXPRESSION(Result, ^) + DOCTEST_FORBIT_EXPRESSION(Result, |) + DOCTEST_FORBIT_EXPRESSION(Result, &&) + DOCTEST_FORBIT_EXPRESSION(Result, ||) + DOCTEST_FORBIT_EXPRESSION(Result, ==) + DOCTEST_FORBIT_EXPRESSION(Result, !=) + DOCTEST_FORBIT_EXPRESSION(Result, <) + DOCTEST_FORBIT_EXPRESSION(Result, >) + DOCTEST_FORBIT_EXPRESSION(Result, <=) + DOCTEST_FORBIT_EXPRESSION(Result, >=) + DOCTEST_FORBIT_EXPRESSION(Result, =) + DOCTEST_FORBIT_EXPRESSION(Result, +=) + DOCTEST_FORBIT_EXPRESSION(Result, -=) + DOCTEST_FORBIT_EXPRESSION(Result, *=) + DOCTEST_FORBIT_EXPRESSION(Result, /=) + DOCTEST_FORBIT_EXPRESSION(Result, %=) + DOCTEST_FORBIT_EXPRESSION(Result, <<=) + DOCTEST_FORBIT_EXPRESSION(Result, >>=) + DOCTEST_FORBIT_EXPRESSION(Result, &=) + DOCTEST_FORBIT_EXPRESSION(Result, ^=) + DOCTEST_FORBIT_EXPRESSION(Result, |=) }; #ifndef DOCTEST_CONFIG_NO_COMPARISON_WARNING_SUPPRESSION @@ -1370,7 +1400,7 @@ namespace detail //DOCTEST_GCC_SUPPRESS_WARNING("-Wfloat-equal") DOCTEST_MSVC_SUPPRESS_WARNING_PUSH - // http://stackoverflow.com/questions/39479163 what's the difference between C4018 and C4389 + // https://stackoverflow.com/questions/39479163 what's the difference between 4018 and 4389 DOCTEST_MSVC_SUPPRESS_WARNING(4388) // signed/unsigned mismatch DOCTEST_MSVC_SUPPRESS_WARNING(4389) // 'operator' : signed/unsigned mismatch DOCTEST_MSVC_SUPPRESS_WARNING(4018) // 'expression' : signed/unsigned mismatch @@ -1378,11 +1408,11 @@ namespace detail #endif // DOCTEST_CONFIG_NO_COMPARISON_WARNING_SUPPRESSION -// clang-format off + // clang-format off #ifndef DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING #define DOCTEST_COMPARISON_RETURN_TYPE bool #else // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING -#define DOCTEST_COMPARISON_RETURN_TYPE typename enable_if::value || can_use_op::value, bool>::type +#define DOCTEST_COMPARISON_RETURN_TYPE typename types::enable_if::value || can_use_op::value, bool>::type inline bool eq(const char* lhs, const char* rhs) { return String(lhs) == String(rhs); } inline bool ne(const char* lhs, const char* rhs) { return String(lhs) != String(rhs); } inline bool lt(const char* lhs, const char* rhs) { return String(lhs) < String(rhs); } @@ -1390,15 +1420,22 @@ namespace detail inline bool le(const char* lhs, const char* rhs) { return String(lhs) <= String(rhs); } inline bool ge(const char* lhs, const char* rhs) { return String(lhs) >= String(rhs); } #endif // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING - - template DOCTEST_COMPARISON_RETURN_TYPE eq(const DOCTEST_REF_WRAP(L) lhs, const DOCTEST_REF_WRAP(R) rhs) { return lhs == rhs; } - template DOCTEST_COMPARISON_RETURN_TYPE ne(const DOCTEST_REF_WRAP(L) lhs, const DOCTEST_REF_WRAP(R) rhs) { return lhs != rhs; } - template DOCTEST_COMPARISON_RETURN_TYPE lt(const DOCTEST_REF_WRAP(L) lhs, const DOCTEST_REF_WRAP(R) rhs) { return lhs < rhs; } - template DOCTEST_COMPARISON_RETURN_TYPE gt(const DOCTEST_REF_WRAP(L) lhs, const DOCTEST_REF_WRAP(R) rhs) { return lhs > rhs; } - template DOCTEST_COMPARISON_RETURN_TYPE le(const DOCTEST_REF_WRAP(L) lhs, const DOCTEST_REF_WRAP(R) rhs) { return lhs <= rhs; } - template DOCTEST_COMPARISON_RETURN_TYPE ge(const DOCTEST_REF_WRAP(L) lhs, const DOCTEST_REF_WRAP(R) rhs) { return lhs >= rhs; } // clang-format on +#define DOCTEST_RELATIONAL_OP(name, op) \ + template \ + DOCTEST_COMPARISON_RETURN_TYPE name(const DOCTEST_REF_WRAP(L) lhs, \ + const DOCTEST_REF_WRAP(R) rhs) { \ + return lhs op rhs; \ + } + + DOCTEST_RELATIONAL_OP(eq, ==) + DOCTEST_RELATIONAL_OP(ne, !=) + DOCTEST_RELATIONAL_OP(lt, <) + DOCTEST_RELATIONAL_OP(gt, >) + DOCTEST_RELATIONAL_OP(le, <=) + DOCTEST_RELATIONAL_OP(ge, >=) + #ifndef DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING #define DOCTEST_CMP_EQ(l, r) l == r #define DOCTEST_CMP_NE(l, r) l != r @@ -1415,46 +1452,35 @@ namespace detail #define DOCTEST_CMP_LE(l, r) le(l, r) #endif // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING -#define DOCTEST_DO_BINARY_EXPRESSION_COMPARISON(op, op_str, op_macro) \ - template \ - DOCTEST_NOINLINE Result operator op(const DOCTEST_REF_WRAP(R) rhs) { \ - bool res = op_macro(lhs, rhs); \ - if(m_assert_type & assertType::is_false) \ - res = !res; \ - if(!res || doctest::detail::getTestsContextState()->success) \ - return Result(res, stringifyBinaryExpr(lhs, op_str, rhs)); \ - return Result(res); \ - } - -#define DOCTEST_FORBIT_EXPRESSION(op) \ - template \ - Expression_lhs& operator op(const R&) { \ - DOCTEST_STATIC_ASSERT(deferred_false::value, \ - Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); \ - return *this; \ - } - template // cppcheck-suppress copyCtorAndEqOperator struct Expression_lhs { L lhs; - assertType::Enum m_assert_type; + assertType::Enum m_at; - explicit Expression_lhs(L in, assertType::Enum at) - : lhs(in) - , m_assert_type(at) {} + explicit Expression_lhs(L&& in, assertType::Enum at) + : lhs(static_cast(in)) + , m_at(at) {} DOCTEST_NOINLINE operator Result() { - bool res = !!lhs; - if(m_assert_type & assertType::is_false) //!OCLINT bitwise operator in conditional +// this is needed only for MSVC 2015 +DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4800) // 'int': forcing value to bool + bool res = static_cast(lhs); +DOCTEST_MSVC_SUPPRESS_WARNING_POP + if(m_at & assertType::is_false) { //!OCLINT bitwise operator in conditional res = !res; + } - if(!res || getTestsContextState()->success) - return Result(res, toString(lhs)); - return Result(res); + if(!res || getContextOptions()->success) { + return { res, (DOCTEST_STRINGIFY(lhs)) }; + } + return { res }; } + /* This is required for user-defined conversions from Expression_lhs to L */ + operator L() const { return lhs; } + // clang-format off DOCTEST_DO_BINARY_EXPRESSION_COMPARISON(==, " == ", DOCTEST_CMP_EQ) //!OCLINT bitwise operator in conditional DOCTEST_DO_BINARY_EXPRESSION_COMPARISON(!=, " != ", DOCTEST_CMP_NE) //!OCLINT bitwise operator in conditional @@ -1464,27 +1490,27 @@ namespace detail DOCTEST_DO_BINARY_EXPRESSION_COMPARISON(<=, " <= ", DOCTEST_CMP_LE) //!OCLINT bitwise operator in conditional // clang-format on - // forbidding some expressions based on this table: http://en.cppreference.com/w/cpp/language/operator_precedence - DOCTEST_FORBIT_EXPRESSION(&) - DOCTEST_FORBIT_EXPRESSION(^) - DOCTEST_FORBIT_EXPRESSION(|) - DOCTEST_FORBIT_EXPRESSION(&&) - DOCTEST_FORBIT_EXPRESSION(||) - DOCTEST_FORBIT_EXPRESSION(=) - DOCTEST_FORBIT_EXPRESSION(+=) - DOCTEST_FORBIT_EXPRESSION(-=) - DOCTEST_FORBIT_EXPRESSION(*=) - DOCTEST_FORBIT_EXPRESSION(/=) - DOCTEST_FORBIT_EXPRESSION(%=) - DOCTEST_FORBIT_EXPRESSION(<<=) - DOCTEST_FORBIT_EXPRESSION(>>=) - DOCTEST_FORBIT_EXPRESSION(&=) - DOCTEST_FORBIT_EXPRESSION(^=) - DOCTEST_FORBIT_EXPRESSION(|=) + // forbidding some expressions based on this table: https://en.cppreference.com/w/cpp/language/operator_precedence + DOCTEST_FORBIT_EXPRESSION(Expression_lhs, &) + DOCTEST_FORBIT_EXPRESSION(Expression_lhs, ^) + DOCTEST_FORBIT_EXPRESSION(Expression_lhs, |) + DOCTEST_FORBIT_EXPRESSION(Expression_lhs, &&) + DOCTEST_FORBIT_EXPRESSION(Expression_lhs, ||) + DOCTEST_FORBIT_EXPRESSION(Expression_lhs, =) + DOCTEST_FORBIT_EXPRESSION(Expression_lhs, +=) + DOCTEST_FORBIT_EXPRESSION(Expression_lhs, -=) + DOCTEST_FORBIT_EXPRESSION(Expression_lhs, *=) + DOCTEST_FORBIT_EXPRESSION(Expression_lhs, /=) + DOCTEST_FORBIT_EXPRESSION(Expression_lhs, %=) + DOCTEST_FORBIT_EXPRESSION(Expression_lhs, <<=) + DOCTEST_FORBIT_EXPRESSION(Expression_lhs, >>=) + DOCTEST_FORBIT_EXPRESSION(Expression_lhs, &=) + DOCTEST_FORBIT_EXPRESSION(Expression_lhs, ^=) + DOCTEST_FORBIT_EXPRESSION(Expression_lhs, |=) // these 2 are unfortunate because they should be allowed - they have higher precedence over the comparisons, but the // ExpressionDecomposer class uses the left shift operator to capture the left operand of the binary expression... - DOCTEST_FORBIT_EXPRESSION(<<) - DOCTEST_FORBIT_EXPRESSION(>>) + DOCTEST_FORBIT_EXPRESSION(Expression_lhs, <<) + DOCTEST_FORBIT_EXPRESSION(Expression_lhs, >>) }; #ifndef DOCTEST_CONFIG_NO_COMPARISON_WARNING_SUPPRESSION @@ -1495,48 +1521,73 @@ namespace detail #endif // DOCTEST_CONFIG_NO_COMPARISON_WARNING_SUPPRESSION - struct ExpressionDecomposer +#if DOCTEST_CLANG && DOCTEST_CLANG < DOCTEST_COMPILER(3, 6, 0) +DOCTEST_CLANG_SUPPRESS_WARNING_POP +#endif + + struct DOCTEST_INTERFACE ExpressionDecomposer { - assertType::Enum m_assert_type; + assertType::Enum m_at; - ExpressionDecomposer(assertType::Enum at) - : m_assert_type(at) {} + ExpressionDecomposer(assertType::Enum at); // The right operator for capturing expressions is "<=" instead of "<<" (based on the operator precedence table) // but then there will be warnings from GCC about "-Wparentheses" and since "_Pragma()" is problematic this will stay for now... - // https://github.com/philsquared/Catch/issues/870 - // https://github.com/philsquared/Catch/issues/565 + // https://github.com/catchorg/Catch2/issues/870 + // https://github.com/catchorg/Catch2/issues/565 template - Expression_lhs operator<<(const DOCTEST_REF_WRAP(L) operand) { - return Expression_lhs(operand, m_assert_type); + Expression_lhs operator<<(L&& operand) { + return Expression_lhs(static_cast(operand), m_at); + } + + template ::value,void >::type* = nullptr> + Expression_lhs operator<<(const L &operand) { + return Expression_lhs(operand, m_at); } }; - struct DOCTEST_INTERFACE TestCase + struct DOCTEST_INTERFACE TestSuite { - // not used for determining uniqueness - funcType m_test; // a function pointer to the test case - String m_full_name; // contains the name (only for templated test cases!) + the template type - const char* m_name; // name of the test case - const char* m_type; // for templated test cases - gets appended to the real name - const char* m_test_suite; // the test suite in which the test was added - const char* m_description; - bool m_skip; - bool m_may_fail; - bool m_should_fail; - int m_expected_failures; - double m_timeout; - - // fields by which uniqueness of test cases shall be determined - const char* m_file; // the file in which the test was registered - unsigned m_line; // the line where the test was registered + const char* m_test_suite = nullptr; + const char* m_description = nullptr; + bool m_skip = false; + bool m_no_breaks = false; + bool m_no_output = false; + bool m_may_fail = false; + bool m_should_fail = false; + int m_expected_failures = 0; + double m_timeout = 0; + + TestSuite& operator*(const char* in); + + template + TestSuite& operator*(const T& in) { + in.fill(*this); + return *this; + } + }; + + using funcType = void (*)(); + + struct DOCTEST_INTERFACE TestCase : public TestCaseData + { + funcType m_test; // a function pointer to the test case + + String m_type; // for templated test cases - gets appended to the real name int m_template_id; // an ID used to distinguish between the different versions of a templated test case + String m_full_name; // contains the name (only for templated test cases!) + the template type TestCase(funcType test, const char* file, unsigned line, const TestSuite& test_suite, - const char* type = "", int template_id = -1); + const String& type = String(), int template_id = -1); + + TestCase(const TestCase& other); + TestCase(TestCase&&) = delete; + + DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(26434) // hides a non-virtual function + TestCase& operator=(const TestCase& other); + DOCTEST_MSVC_SUPPRESS_WARNING_POP - // for gcc 4.7 - DOCTEST_NOINLINE ~TestCase() {} + TestCase& operator=(TestCase&&) = delete; TestCase& operator*(const char* in); @@ -1546,19 +1597,20 @@ namespace detail return *this; } - TestCase(const TestCase& other) { *this = other; } - - TestCase& operator=(const TestCase& other); - bool operator<(const TestCase& other) const; + + ~TestCase() = default; }; // forward declarations of functions used by the macros - DOCTEST_INTERFACE int regTest(const TestCase& tc); - DOCTEST_INTERFACE int setTestSuite(const TestSuite& ts); + DOCTEST_INTERFACE int regTest(const TestCase& tc); + DOCTEST_INTERFACE int setTestSuite(const TestSuite& ts); + DOCTEST_INTERFACE bool isDebuggerActive(); - namespace binaryAssertComparison - { + template + int instantiationHelper(const T&) { return 0; } + + namespace binaryAssertComparison { enum Enum { eq = 0, @@ -1572,62 +1624,60 @@ namespace detail // clang-format off template struct RelationalComparator { bool operator()(const DOCTEST_REF_WRAP(L), const DOCTEST_REF_WRAP(R) ) const { return false; } }; - template struct RelationalComparator<0, L, R> { bool operator()(const DOCTEST_REF_WRAP(L) lhs, const DOCTEST_REF_WRAP(R) rhs) const { return eq(lhs, rhs); } }; - template struct RelationalComparator<1, L, R> { bool operator()(const DOCTEST_REF_WRAP(L) lhs, const DOCTEST_REF_WRAP(R) rhs) const { return ne(lhs, rhs); } }; - template struct RelationalComparator<2, L, R> { bool operator()(const DOCTEST_REF_WRAP(L) lhs, const DOCTEST_REF_WRAP(R) rhs) const { return gt(lhs, rhs); } }; - template struct RelationalComparator<3, L, R> { bool operator()(const DOCTEST_REF_WRAP(L) lhs, const DOCTEST_REF_WRAP(R) rhs) const { return lt(lhs, rhs); } }; - template struct RelationalComparator<4, L, R> { bool operator()(const DOCTEST_REF_WRAP(L) lhs, const DOCTEST_REF_WRAP(R) rhs) const { return ge(lhs, rhs); } }; - template struct RelationalComparator<5, L, R> { bool operator()(const DOCTEST_REF_WRAP(L) lhs, const DOCTEST_REF_WRAP(R) rhs) const { return le(lhs, rhs); } }; + +#define DOCTEST_BINARY_RELATIONAL_OP(n, op) \ + template struct RelationalComparator { bool operator()(const DOCTEST_REF_WRAP(L) lhs, const DOCTEST_REF_WRAP(R) rhs) const { return op(lhs, rhs); } }; // clang-format on - struct DOCTEST_INTERFACE ResultBuilder - { - assertType::Enum m_assert_type; - const char* m_file; - int m_line; - const char* m_expr; - const char* m_exception_type; - - Result m_result; - bool m_threw; - bool m_threw_as; - bool m_failed; - String m_exception; + DOCTEST_BINARY_RELATIONAL_OP(0, doctest::detail::eq) + DOCTEST_BINARY_RELATIONAL_OP(1, doctest::detail::ne) + DOCTEST_BINARY_RELATIONAL_OP(2, doctest::detail::gt) + DOCTEST_BINARY_RELATIONAL_OP(3, doctest::detail::lt) + DOCTEST_BINARY_RELATIONAL_OP(4, doctest::detail::ge) + DOCTEST_BINARY_RELATIONAL_OP(5, doctest::detail::le) + struct DOCTEST_INTERFACE ResultBuilder : public AssertData + { ResultBuilder(assertType::Enum at, const char* file, int line, const char* expr, - const char* exception_type = ""); + const char* exception_type = "", const String& exception_string = ""); - ~ResultBuilder(); + ResultBuilder(assertType::Enum at, const char* file, int line, const char* expr, + const char* exception_type, const Contains& exception_string); - void setResult(const Result& res) { m_result = res; } + void setResult(const Result& res); template - DOCTEST_NOINLINE void binary_assert(const DOCTEST_REF_WRAP(L) lhs, + DOCTEST_NOINLINE bool binary_assert(const DOCTEST_REF_WRAP(L) lhs, const DOCTEST_REF_WRAP(R) rhs) { - m_result.m_passed = RelationalComparator()(lhs, rhs); - if(!m_result.m_passed || getTestsContextState()->success) - m_result.m_decomposition = stringifyBinaryExpr(lhs, ", ", rhs); + m_failed = !RelationalComparator()(lhs, rhs); + if (m_failed || getContextOptions()->success) { + m_decomp = stringifyBinaryExpr(lhs, ", ", rhs); + } + return !m_failed; } template - DOCTEST_NOINLINE void unary_assert(const DOCTEST_REF_WRAP(L) val) { - m_result.m_passed = !!val; + DOCTEST_NOINLINE bool unary_assert(const DOCTEST_REF_WRAP(L) val) { + m_failed = !val; - if(m_assert_type & assertType::is_false) //!OCLINT bitwise operator in conditional - m_result.m_passed = !m_result.m_passed; + if (m_at & assertType::is_false) { //!OCLINT bitwise operator in conditional + m_failed = !m_failed; + } + + if (m_failed || getContextOptions()->success) { + m_decomp = (DOCTEST_STRINGIFY(val)); + } - if(!m_result.m_passed || getTestsContextState()->success) - m_result.m_decomposition = toString(val); + return !m_failed; } - void unexpectedExceptionOccurred(); + void translateException(); bool log(); void react() const; }; - namespace assertAction - { + namespace assertAction { enum Enum { nothing = 0, @@ -1636,75 +1686,73 @@ namespace detail }; } // namespace assertAction - template - DOCTEST_NOINLINE int fast_binary_assert(assertType::Enum at, const char* file, int line, - const char* expr, const DOCTEST_REF_WRAP(L) lhs, - const DOCTEST_REF_WRAP(R) rhs) { - ResultBuilder rb(at, file, line, expr); + DOCTEST_INTERFACE void failed_out_of_a_testing_context(const AssertData& ad); - rb.m_result.m_passed = RelationalComparator()(lhs, rhs); + DOCTEST_INTERFACE bool decomp_assert(assertType::Enum at, const char* file, int line, + const char* expr, const Result& result); - if(!rb.m_result.m_passed || getTestsContextState()->success) - rb.m_result.m_decomposition = stringifyBinaryExpr(lhs, ", ", rhs); - - int res = 0; +#define DOCTEST_ASSERT_OUT_OF_TESTS(decomp) \ + do { \ + if(!is_running_in_test) { \ + if(failed) { \ + ResultBuilder rb(at, file, line, expr); \ + rb.m_failed = failed; \ + rb.m_decomp = decomp; \ + failed_out_of_a_testing_context(rb); \ + if(isDebuggerActive() && !getContextOptions()->no_breaks) \ + DOCTEST_BREAK_INTO_DEBUGGER(); \ + if(checkIfShouldThrow(at)) \ + throwException(); \ + } \ + return !failed; \ + } \ + } while(false) - if(rb.log()) - res |= assertAction::dbgbreak; +#define DOCTEST_ASSERT_IN_TESTS(decomp) \ + ResultBuilder rb(at, file, line, expr); \ + rb.m_failed = failed; \ + if(rb.m_failed || getContextOptions()->success) \ + rb.m_decomp = decomp; \ + if(rb.log()) \ + DOCTEST_BREAK_INTO_DEBUGGER(); \ + if(rb.m_failed && checkIfShouldThrow(at)) \ + throwException() - if(rb.m_failed && checkIfShouldThrow(at)) - res |= assertAction::shouldthrow; + template + DOCTEST_NOINLINE bool binary_assert(assertType::Enum at, const char* file, int line, + const char* expr, const DOCTEST_REF_WRAP(L) lhs, + const DOCTEST_REF_WRAP(R) rhs) { + bool failed = !RelationalComparator()(lhs, rhs); -#ifdef DOCTEST_CONFIG_SUPER_FAST_ASSERTS - // ######################################################################################### - // IF THE DEBUGGER BREAKS HERE - GO 1 LEVEL UP IN THE CALLSTACK TO SEE THE FAILING ASSERTION + // ################################################################################### + // IF THE DEBUGGER BREAKS HERE - GO 1 LEVEL UP IN THE CALLSTACK FOR THE FAILING ASSERT // THIS IS THE EFFECT OF HAVING 'DOCTEST_CONFIG_SUPER_FAST_ASSERTS' DEFINED - // ######################################################################################### - if(res & assertAction::dbgbreak) - DOCTEST_BREAK_INTO_DEBUGGER(); - fastAssertThrowIfFlagSet(res); -#endif // DOCTEST_CONFIG_SUPER_FAST_ASSERTS - - return res; + // ################################################################################### + DOCTEST_ASSERT_OUT_OF_TESTS(stringifyBinaryExpr(lhs, ", ", rhs)); + DOCTEST_ASSERT_IN_TESTS(stringifyBinaryExpr(lhs, ", ", rhs)); + return !failed; } template - DOCTEST_NOINLINE int fast_unary_assert(assertType::Enum at, const char* file, int line, - const char* val_str, const DOCTEST_REF_WRAP(L) val) { - ResultBuilder rb(at, file, line, val_str); - - rb.m_result.m_passed = !!val; + DOCTEST_NOINLINE bool unary_assert(assertType::Enum at, const char* file, int line, + const char* expr, const DOCTEST_REF_WRAP(L) val) { + bool failed = !val; if(at & assertType::is_false) //!OCLINT bitwise operator in conditional - rb.m_result.m_passed = !rb.m_result.m_passed; - - if(!rb.m_result.m_passed || getTestsContextState()->success) - rb.m_result.m_decomposition = toString(val); - - int res = 0; - - if(rb.log()) - res |= assertAction::dbgbreak; + failed = !failed; - if(rb.m_failed && checkIfShouldThrow(at)) - res |= assertAction::shouldthrow; - -#ifdef DOCTEST_CONFIG_SUPER_FAST_ASSERTS - // ######################################################################################### - // IF THE DEBUGGER BREAKS HERE - GO 1 LEVEL UP IN THE CALLSTACK TO SEE THE FAILING ASSERTION + // ################################################################################### + // IF THE DEBUGGER BREAKS HERE - GO 1 LEVEL UP IN THE CALLSTACK FOR THE FAILING ASSERT // THIS IS THE EFFECT OF HAVING 'DOCTEST_CONFIG_SUPER_FAST_ASSERTS' DEFINED - // ######################################################################################### - if(res & assertAction::dbgbreak) - DOCTEST_BREAK_INTO_DEBUGGER(); - fastAssertThrowIfFlagSet(res); -#endif // DOCTEST_CONFIG_SUPER_FAST_ASSERTS - - return res; + // ################################################################################### + DOCTEST_ASSERT_OUT_OF_TESTS((DOCTEST_STRINGIFY(val))); + DOCTEST_ASSERT_IN_TESTS((DOCTEST_STRINGIFY(val))); + return !failed; } struct DOCTEST_INTERFACE IExceptionTranslator { - virtual ~IExceptionTranslator() {} + DOCTEST_DECLARE_INTERFACE(IExceptionTranslator) virtual bool translate(String&) const = 0; }; @@ -1715,326 +1763,132 @@ namespace detail explicit ExceptionTranslator(String (*translateFunction)(T)) : m_translateFunction(translateFunction) {} - bool translate(String& res) const { + bool translate(String& res) const override { #ifndef DOCTEST_CONFIG_NO_EXCEPTIONS try { - throw; + throw; // lgtm [cpp/rethrow-no-exception] // cppcheck-suppress catchExceptionByValue - } catch(T ex) { // NOLINT + } catch(const T& ex) { res = m_translateFunction(ex); //!OCLINT parameter reassignment return true; - } catch(...) {} //!OCLINT - empty catch statement -#endif // DOCTEST_CONFIG_NO_EXCEPTIONS - ((void)res); // to silence -Wunused-parameter + } catch(...) {} //!OCLINT - empty catch statement +#endif // DOCTEST_CONFIG_NO_EXCEPTIONS + static_cast(res); // to silence -Wunused-parameter return false; } - protected: + private: String (*m_translateFunction)(T); }; - DOCTEST_INTERFACE void registerExceptionTranslatorImpl( - const IExceptionTranslator* translateFunction); - - // FIX FOR VISUAL STUDIO VERSIONS PRIOR TO 2015 - they failed to compile the call to operator<< with - // std::ostream passed as a reference noting that there is a use of an undefined type (which there isn't) - DOCTEST_INTERFACE void writeStringToStream(std::ostream* s, const String& str); - - template - struct StringStreamBase - { - template - static void convert(std::ostream* s, const T& in) { - writeStringToStream(s, toString(in)); - } + DOCTEST_INTERFACE void registerExceptionTranslatorImpl(const IExceptionTranslator* et); - // always treat char* as a string in this context - no matter - // if DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING is defined - static void convert(std::ostream* s, const char* in) { writeStringToStream(s, String(in)); } - }; + // ContextScope base class used to allow implementing methods of ContextScope + // that don't depend on the template parameter in doctest.cpp. + struct DOCTEST_INTERFACE ContextScopeBase : public IContextScope { + ContextScopeBase(const ContextScopeBase&) = delete; - template <> - struct StringStreamBase - { - template - static void convert(std::ostream* s, const T& in) { - *s << in; - } - }; + ContextScopeBase& operator=(const ContextScopeBase&) = delete; + ContextScopeBase& operator=(ContextScopeBase&&) = delete; - template - struct StringStream : StringStreamBase::value> - {}; + ~ContextScopeBase() override = default; - template - void toStream(std::ostream* s, const T& value) { - StringStream::convert(s, value); - } + protected: + ContextScopeBase(); + ContextScopeBase(ContextScopeBase&& other) noexcept; -#ifdef DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING - DOCTEST_INTERFACE void toStream(std::ostream* s, char* in); - DOCTEST_INTERFACE void toStream(std::ostream* s, const char* in); -#endif // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING - DOCTEST_INTERFACE void toStream(std::ostream* s, bool in); - DOCTEST_INTERFACE void toStream(std::ostream* s, float in); - DOCTEST_INTERFACE void toStream(std::ostream* s, double in); - DOCTEST_INTERFACE void toStream(std::ostream* s, double long in); - - DOCTEST_INTERFACE void toStream(std::ostream* s, char in); - DOCTEST_INTERFACE void toStream(std::ostream* s, char signed in); - DOCTEST_INTERFACE void toStream(std::ostream* s, char unsigned in); - DOCTEST_INTERFACE void toStream(std::ostream* s, int short in); - DOCTEST_INTERFACE void toStream(std::ostream* s, int short unsigned in); - DOCTEST_INTERFACE void toStream(std::ostream* s, int in); - DOCTEST_INTERFACE void toStream(std::ostream* s, int unsigned in); - DOCTEST_INTERFACE void toStream(std::ostream* s, int long in); - DOCTEST_INTERFACE void toStream(std::ostream* s, int long unsigned in); - -#ifdef DOCTEST_CONFIG_WITH_LONG_LONG - DOCTEST_INTERFACE void toStream(std::ostream* s, int long long in); - DOCTEST_INTERFACE void toStream(std::ostream* s, int long long unsigned in); -#endif // DOCTEST_CONFIG_WITH_LONG_LONG - - struct IContextScope - { - virtual ~IContextScope() {} - virtual void build(std::ostream*) = 0; + void destroy(); + bool need_to_destroy{true}; }; - DOCTEST_INTERFACE void addToContexts(IContextScope* ptr); - DOCTEST_INTERFACE void popFromContexts(); - DOCTEST_INTERFACE void useContextIfExceptionOccurred(IContextScope* ptr); - - // cppcheck-suppress copyCtorAndEqOperator - class ContextBuilder + template class ContextScope : public ContextScopeBase { - friend class ContextScope; - - struct ICapture - { - virtual ~ICapture() {} - virtual void toStream(std::ostream*) const = 0; - }; - - template - struct Capture : ICapture //!OCLINT destructor of virtual class - { - const T* capture; - - explicit Capture(const T* in) - : capture(in) {} - virtual void toStream(std::ostream* s) const { // override - detail::toStream(s, *capture); - } - }; - - struct Chunk - { - char buf[sizeof(Capture)] DOCTEST_ALIGNMENT( - 2 * sizeof(void*)); // place to construct a Capture - }; - - struct Node - { - Chunk chunk; - Node* next; - }; - - Chunk stackChunks[DOCTEST_CONFIG_NUM_CAPTURES_ON_STACK]; - int numCaptures; - Node* head; - Node* tail; - - DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH("-Wcast-align") - void build(std::ostream* s) const { - int curr = 0; - // iterate over small buffer - while(curr < numCaptures && curr < DOCTEST_CONFIG_NUM_CAPTURES_ON_STACK) - reinterpret_cast(stackChunks[curr++].buf)->toStream(s); - // iterate over list - Node* curr_elem = head; - while(curr < numCaptures) { - reinterpret_cast(curr_elem->chunk.buf)->toStream(s); - curr_elem = curr_elem->next; - ++curr; - } - } - DOCTEST_GCC_SUPPRESS_WARNING_POP - - // steal the contents of the other - acting as a move constructor... - DOCTEST_NOINLINE ContextBuilder(ContextBuilder& other) - : numCaptures(other.numCaptures) - , head(other.head) - , tail(other.tail) { - other.numCaptures = 0; - other.head = 0; - other.tail = 0; - my_memcpy(stackChunks, other.stackChunks, - unsigned(int(sizeof(Chunk)) * DOCTEST_CONFIG_NUM_CAPTURES_ON_STACK)); - } - - ContextBuilder& operator=(const ContextBuilder&); // NOLINT + L lambda_; public: - // cppcheck-suppress uninitMemberVar - DOCTEST_NOINLINE ContextBuilder() // NOLINT - : numCaptures(0) - , head(0) - , tail(0) {} + explicit ContextScope(const L &lambda) : lambda_(lambda) {} + explicit ContextScope(L&& lambda) : lambda_(static_cast(lambda)) { } - template - DOCTEST_NOINLINE ContextBuilder& operator<<(T& in) { - Capture temp(&in); - - // construct either on stack or on heap - // copy the bytes for the whole object - including the vtable because we cant construct - // the object directly in the buffer using placement new - need the header... - if(numCaptures < DOCTEST_CONFIG_NUM_CAPTURES_ON_STACK) { - my_memcpy(stackChunks[numCaptures].buf, &temp, sizeof(Chunk)); - } else { - Node* curr = new Node; - curr->next = 0; - if(tail) { - tail->next = curr; - tail = curr; - } else { - head = tail = curr; - } + ContextScope(const ContextScope&) = delete; + ContextScope(ContextScope&&) noexcept = default; - my_memcpy(tail->chunk.buf, &temp, sizeof(Chunk)); - } - ++numCaptures; - return *this; - } + ContextScope& operator=(const ContextScope&) = delete; + ContextScope& operator=(ContextScope&&) = delete; - DOCTEST_NOINLINE ~ContextBuilder() { - // free the linked list - the ones on the stack are left as-is - // no destructors are called at all - there is no need - while(head) { - Node* next = head->next; - delete head; - head = next; - } - } + void stringify(std::ostream* s) const override { lambda_(s); } -#ifdef DOCTEST_CONFIG_WITH_RVALUE_REFERENCES - template - ContextBuilder& operator<<(const T&&) { - DOCTEST_STATIC_ASSERT( - deferred_false::value, - Cannot_pass_temporaries_or_rvalues_to_the_streaming_operator_because_it_caches_pointers_to_the_passed_objects_for_lazy_evaluation); - return *this; + ~ContextScope() override { + if (need_to_destroy) { + destroy(); + } } -#endif // DOCTEST_CONFIG_WITH_RVALUE_REFERENCES }; - class ContextScope : public IContextScope + struct DOCTEST_INTERFACE MessageBuilder : public MessageData { - ContextBuilder contextBuilder; + std::ostream* m_stream; + bool logged = false; - public: - DOCTEST_NOINLINE explicit ContextScope(ContextBuilder& temp) - : contextBuilder(temp) { - addToContexts(this); - } - - DOCTEST_NOINLINE ~ContextScope() { - useContextIfExceptionOccurred(this); - popFromContexts(); - } + MessageBuilder(const char* file, int line, assertType::Enum severity); - void build(std::ostream* s) { contextBuilder.build(s); } - }; + MessageBuilder(const MessageBuilder&) = delete; + MessageBuilder(MessageBuilder&&) = delete; - class DOCTEST_INTERFACE MessageBuilder - { - std::ostream* m_stream; - const char* m_file; - int m_line; - assertType::Enum m_severity; + MessageBuilder& operator=(const MessageBuilder&) = delete; + MessageBuilder& operator=(MessageBuilder&&) = delete; - public: - MessageBuilder(const char* file, int line, assertType::Enum severity); ~MessageBuilder(); + // the preferred way of chaining parameters for stringification +DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4866) template - MessageBuilder& operator<<(const T& in) { - toStream(m_stream, in); + MessageBuilder& operator,(const T& in) { + *m_stream << (DOCTEST_STRINGIFY(in)); return *this; } +DOCTEST_MSVC_SUPPRESS_WARNING_POP + + // kept here just for backwards-compatibility - the comma operator should be preferred now + template + MessageBuilder& operator<<(const T& in) { return this->operator,(in); } + + // the `,` operator has the lowest operator precedence - if `<<` is used by the user then + // the `,` operator will be called last which is not what we want and thus the `*` operator + // is used first (has higher operator precedence compared to `<<`) so that we guarantee that + // an operator of the MessageBuilder class is called first before the rest of the parameters + template + MessageBuilder& operator*(const T& in) { return this->operator,(in); } - void log(std::ostream&); bool log(); void react(); }; -} // namespace detail - -struct test_suite -{ - const char* data; - test_suite(const char* in) - : data(in) {} - void fill(detail::TestCase& state) const { state.m_test_suite = data; } - void fill(detail::TestSuite& state) const { state.m_test_suite = data; } -}; - -struct description -{ - const char* data; - description(const char* in) - : data(in) {} - void fill(detail::TestCase& state) const { state.m_description = data; } - void fill(detail::TestSuite& state) const { state.m_description = data; } -}; - -struct skip -{ - bool data; - skip(bool in = true) - : data(in) {} - void fill(detail::TestCase& state) const { state.m_skip = data; } - void fill(detail::TestSuite& state) const { state.m_skip = data; } -}; - -struct timeout -{ - double data; - timeout(double in) - : data(in) {} - void fill(detail::TestCase& state) const { state.m_timeout = data; } - void fill(detail::TestSuite& state) const { state.m_timeout = data; } -}; - -struct may_fail -{ - bool data; - may_fail(bool in = true) - : data(in) {} - void fill(detail::TestCase& state) const { state.m_may_fail = data; } - void fill(detail::TestSuite& state) const { state.m_may_fail = data; } -}; -struct should_fail -{ - bool data; - should_fail(bool in = true) - : data(in) {} - void fill(detail::TestCase& state) const { state.m_should_fail = data; } - void fill(detail::TestSuite& state) const { state.m_should_fail = data; } -}; + template + ContextScope MakeContextScope(const L &lambda) { + return ContextScope(lambda); + } +} // namespace detail -struct expected_failures -{ - int data; - expected_failures(int in) - : data(in) {} - void fill(detail::TestCase& state) const { state.m_expected_failures = data; } - void fill(detail::TestSuite& state) const { state.m_expected_failures = data; } -}; +#define DOCTEST_DEFINE_DECORATOR(name, type, def) \ + struct name \ + { \ + type data; \ + name(type in = def) \ + : data(in) {} \ + void fill(detail::TestCase& state) const { state.DOCTEST_CAT(m_, name) = data; } \ + void fill(detail::TestSuite& state) const { state.DOCTEST_CAT(m_, name) = data; } \ + } -#endif // DOCTEST_CONFIG_DISABLE +DOCTEST_DEFINE_DECORATOR(test_suite, const char*, ""); +DOCTEST_DEFINE_DECORATOR(description, const char*, ""); +DOCTEST_DEFINE_DECORATOR(skip, bool, true); +DOCTEST_DEFINE_DECORATOR(no_breaks, bool, true); +DOCTEST_DEFINE_DECORATOR(no_output, bool, true); +DOCTEST_DEFINE_DECORATOR(timeout, double, 0); +DOCTEST_DEFINE_DECORATOR(may_fail, bool, true); +DOCTEST_DEFINE_DECORATOR(should_fail, bool, true); +DOCTEST_DEFINE_DECORATOR(expected_failures, int, 0); -#ifndef DOCTEST_CONFIG_DISABLE template int registerExceptionTranslator(String (*translateFunction)(T)) { DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wexit-time-destructors") @@ -2044,6 +1898,15 @@ int registerExceptionTranslator(String (*translateFunction)(T)) { return 0; } +} // namespace doctest + +// in a separate namespace outside of doctest because the DOCTEST_TEST_SUITE macro +// introduces an anonymous namespace in which getCurrentTestSuite gets overridden +namespace doctest_detail_test_suite_ns { +DOCTEST_INTERFACE doctest::detail::TestSuite& getCurrentTestSuite(); +} // namespace doctest_detail_test_suite_ns + +namespace doctest { #else // DOCTEST_CONFIG_DISABLE template int registerExceptionTranslator(String (*)(T)) { @@ -2051,214 +1914,341 @@ int registerExceptionTranslator(String (*)(T)) { } #endif // DOCTEST_CONFIG_DISABLE -DOCTEST_INTERFACE bool isRunningInTest(); +namespace detail { + using assert_handler = void (*)(const AssertData&); + struct ContextState; +} // namespace detail -// cppcheck-suppress noCopyConstructor class DOCTEST_INTERFACE Context { -#if !defined(DOCTEST_CONFIG_DISABLE) detail::ContextState* p; void parseArgs(int argc, const char* const* argv, bool withDefaults = false); -#endif // DOCTEST_CONFIG_DISABLE - public: - explicit Context(int argc = 0, const char* const* argv = 0); + explicit Context(int argc = 0, const char* const* argv = nullptr); - ~Context(); + Context(const Context&) = delete; + Context(Context&&) = delete; + + Context& operator=(const Context&) = delete; + Context& operator=(Context&&) = delete; + + ~Context(); // NOLINT(performance-trivially-destructible) void applyCommandLine(int argc, const char* const* argv); void addFilter(const char* filter, const char* value); void clearFilters(); + void setOption(const char* option, bool value); void setOption(const char* option, int value); void setOption(const char* option, const char* value); bool shouldExit(); + void setAsDefaultForAssertsOutOfTestCases(); + + void setAssertHandler(detail::assert_handler ah); + + void setCout(std::ostream* out); + int run(); }; +namespace TestCaseFailureReason { + enum Enum + { + None = 0, + AssertFailure = 1, // an assertion has failed in the test case + Exception = 2, // test case threw an exception + Crash = 4, // a crash... + TooManyFailedAsserts = 8, // the abort-after option + Timeout = 16, // see the timeout decorator + ShouldHaveFailedButDidnt = 32, // see the should_fail decorator + ShouldHaveFailedAndDid = 64, // see the should_fail decorator + DidntFailExactlyNumTimes = 128, // see the expected_failures decorator + FailedExactlyNumTimes = 256, // see the expected_failures decorator + CouldHaveFailedAndDid = 512 // see the may_fail decorator + }; +} // namespace TestCaseFailureReason + +struct DOCTEST_INTERFACE CurrentTestCaseStats +{ + int numAssertsCurrentTest; + int numAssertsFailedCurrentTest; + double seconds; + int failure_flags; // use TestCaseFailureReason::Enum + bool testCaseSuccess; +}; + +struct DOCTEST_INTERFACE TestCaseException +{ + String error_string; + bool is_crash; +}; + +struct DOCTEST_INTERFACE TestRunStats +{ + unsigned numTestCases; + unsigned numTestCasesPassingFilters; + unsigned numTestSuitesPassingFilters; + unsigned numTestCasesFailed; + int numAsserts; + int numAssertsFailed; +}; + +struct QueryData +{ + const TestRunStats* run_stats = nullptr; + const TestCaseData** data = nullptr; + unsigned num_data = 0; +}; + +struct DOCTEST_INTERFACE IReporter +{ + // The constructor has to accept "const ContextOptions&" as a single argument + // which has most of the options for the run + a pointer to the stdout stream + // Reporter(const ContextOptions& in) + + // called when a query should be reported (listing test cases, printing the version, etc.) + virtual void report_query(const QueryData&) = 0; + + // called when the whole test run starts + virtual void test_run_start() = 0; + // called when the whole test run ends (caching a pointer to the input doesn't make sense here) + virtual void test_run_end(const TestRunStats&) = 0; + + // called when a test case is started (safe to cache a pointer to the input) + virtual void test_case_start(const TestCaseData&) = 0; + // called when a test case is reentered because of unfinished subcases (safe to cache a pointer to the input) + virtual void test_case_reenter(const TestCaseData&) = 0; + // called when a test case has ended + virtual void test_case_end(const CurrentTestCaseStats&) = 0; + + // called when an exception is thrown from the test case (or it crashes) + virtual void test_case_exception(const TestCaseException&) = 0; + + // called whenever a subcase is entered (don't cache pointers to the input) + virtual void subcase_start(const SubcaseSignature&) = 0; + // called whenever a subcase is exited (don't cache pointers to the input) + virtual void subcase_end() = 0; + + // called for each assert (don't cache pointers to the input) + virtual void log_assert(const AssertData&) = 0; + // called for each message (don't cache pointers to the input) + virtual void log_message(const MessageData&) = 0; + + // called when a test case is skipped either because it doesn't pass the filters, has a skip decorator + // or isn't in the execution range (between first and last) (safe to cache a pointer to the input) + virtual void test_case_skipped(const TestCaseData&) = 0; + + DOCTEST_DECLARE_INTERFACE(IReporter) + + // can obtain all currently active contexts and stringify them if one wishes to do so + static int get_num_active_contexts(); + static const IContextScope* const* get_active_contexts(); + + // can iterate through contexts which have been stringified automatically in their destructors when an exception has been thrown + static int get_num_stringified_contexts(); + static const String* get_stringified_contexts(); +}; + +namespace detail { + using reporterCreatorFunc = IReporter* (*)(const ContextOptions&); + + DOCTEST_INTERFACE void registerReporterImpl(const char* name, int prio, reporterCreatorFunc c, bool isReporter); + + template + IReporter* reporterCreator(const ContextOptions& o) { + return new Reporter(o); + } +} // namespace detail + +template +int registerReporter(const char* name, int priority, bool isReporter) { + detail::registerReporterImpl(name, priority, detail::reporterCreator, isReporter); + return 0; +} } // namespace doctest +#ifdef DOCTEST_CONFIG_ASSERTS_RETURN_VALUES +#define DOCTEST_FUNC_EMPTY [] { return false; }() +#else +#define DOCTEST_FUNC_EMPTY (void)0 +#endif + // if registering is not disabled -#if !defined(DOCTEST_CONFIG_DISABLE) +#ifndef DOCTEST_CONFIG_DISABLE + +#ifdef DOCTEST_CONFIG_ASSERTS_RETURN_VALUES +#define DOCTEST_FUNC_SCOPE_BEGIN [&] +#define DOCTEST_FUNC_SCOPE_END () +#define DOCTEST_FUNC_SCOPE_RET(v) return v +#else +#define DOCTEST_FUNC_SCOPE_BEGIN do +#define DOCTEST_FUNC_SCOPE_END while(false) +#define DOCTEST_FUNC_SCOPE_RET(v) (void)0 +#endif + +// common code in asserts - for convenience +#define DOCTEST_ASSERT_LOG_REACT_RETURN(b) \ + if(b.log()) DOCTEST_BREAK_INTO_DEBUGGER(); \ + b.react(); \ + DOCTEST_FUNC_SCOPE_RET(!b.m_failed) -#ifdef DOCTEST_CONFIG_WITH_VARIADIC_MACROS -#define DOCTEST_EXPAND_VA_ARGS(...) __VA_ARGS__ -#else // DOCTEST_CONFIG_WITH_VARIADIC_MACROS -#define DOCTEST_EXPAND_VA_ARGS -#endif // DOCTEST_CONFIG_WITH_VARIADIC_MACROS +#ifdef DOCTEST_CONFIG_NO_TRY_CATCH_IN_ASSERTS +#define DOCTEST_WRAP_IN_TRY(x) x; +#else // DOCTEST_CONFIG_NO_TRY_CATCH_IN_ASSERTS +#define DOCTEST_WRAP_IN_TRY(x) \ + try { \ + x; \ + } catch(...) { DOCTEST_RB.translateException(); } +#endif // DOCTEST_CONFIG_NO_TRY_CATCH_IN_ASSERTS -#define DOCTEST_STRIP_PARENS(x) x -#define DOCTEST_HANDLE_BRACED_VA_ARGS(expr) DOCTEST_STRIP_PARENS(DOCTEST_EXPAND_VA_ARGS expr) +#ifdef DOCTEST_CONFIG_VOID_CAST_EXPRESSIONS +#define DOCTEST_CAST_TO_VOID(...) \ + DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH("-Wuseless-cast") \ + static_cast(__VA_ARGS__); \ + DOCTEST_GCC_SUPPRESS_WARNING_POP +#else // DOCTEST_CONFIG_VOID_CAST_EXPRESSIONS +#define DOCTEST_CAST_TO_VOID(...) __VA_ARGS__; +#endif // DOCTEST_CONFIG_VOID_CAST_EXPRESSIONS // registers the test by initializing a dummy var with a function -#define DOCTEST_REGISTER_FUNCTION(f, decorators) \ - DOCTEST_GLOBAL_NO_WARNINGS(DOCTEST_ANONYMOUS(_DOCTEST_ANON_VAR_)) = doctest::detail::regTest( \ - doctest::detail::TestCase(f, __FILE__, __LINE__, \ - doctest_detail_test_suite_ns::getCurrentTestSuite()) * \ - decorators); \ - DOCTEST_GLOBAL_NO_WARNINGS_END() +#define DOCTEST_REGISTER_FUNCTION(global_prefix, f, decorators) \ + global_prefix DOCTEST_GLOBAL_NO_WARNINGS(DOCTEST_ANONYMOUS(DOCTEST_ANON_VAR_), /* NOLINT */ \ + doctest::detail::regTest( \ + doctest::detail::TestCase( \ + f, __FILE__, __LINE__, \ + doctest_detail_test_suite_ns::getCurrentTestSuite()) * \ + decorators)) #define DOCTEST_IMPLEMENT_FIXTURE(der, base, func, decorators) \ - namespace \ - { \ - struct der : base \ + namespace { /* NOLINT */ \ + struct der : public base \ { \ void f(); \ }; \ - static void func() { \ + static inline DOCTEST_NOINLINE void func() { \ der v; \ v.f(); \ } \ - DOCTEST_REGISTER_FUNCTION(func, decorators) \ + DOCTEST_REGISTER_FUNCTION(DOCTEST_EMPTY, func, decorators) \ } \ - inline DOCTEST_NOINLINE void der::f() + inline DOCTEST_NOINLINE void der::f() // NOLINT(misc-definitions-in-headers) #define DOCTEST_CREATE_AND_REGISTER_FUNCTION(f, decorators) \ static void f(); \ - DOCTEST_REGISTER_FUNCTION(f, decorators) \ + DOCTEST_REGISTER_FUNCTION(DOCTEST_EMPTY, f, decorators) \ + static void f() + +#define DOCTEST_CREATE_AND_REGISTER_FUNCTION_IN_CLASS(f, proxy, decorators) \ + static doctest::detail::funcType proxy() { return f; } \ + DOCTEST_REGISTER_FUNCTION(inline, proxy(), decorators) \ static void f() // for registering tests #define DOCTEST_TEST_CASE(decorators) \ - DOCTEST_CREATE_AND_REGISTER_FUNCTION(DOCTEST_ANONYMOUS(_DOCTEST_ANON_FUNC_), decorators) + DOCTEST_CREATE_AND_REGISTER_FUNCTION(DOCTEST_ANONYMOUS(DOCTEST_ANON_FUNC_), decorators) + +// for registering tests in classes - requires C++17 for inline variables! +#if DOCTEST_CPLUSPLUS >= 201703L +#define DOCTEST_TEST_CASE_CLASS(decorators) \ + DOCTEST_CREATE_AND_REGISTER_FUNCTION_IN_CLASS(DOCTEST_ANONYMOUS(DOCTEST_ANON_FUNC_), \ + DOCTEST_ANONYMOUS(DOCTEST_ANON_PROXY_), \ + decorators) +#else // DOCTEST_TEST_CASE_CLASS +#define DOCTEST_TEST_CASE_CLASS(...) \ + TEST_CASES_CAN_BE_REGISTERED_IN_CLASSES_ONLY_IN_CPP17_MODE_OR_WITH_VS_2017_OR_NEWER +#endif // DOCTEST_TEST_CASE_CLASS // for registering tests with a fixture #define DOCTEST_TEST_CASE_FIXTURE(c, decorators) \ - DOCTEST_IMPLEMENT_FIXTURE(DOCTEST_ANONYMOUS(_DOCTEST_ANON_CLASS_), c, \ - DOCTEST_ANONYMOUS(_DOCTEST_ANON_FUNC_), decorators) + DOCTEST_IMPLEMENT_FIXTURE(DOCTEST_ANONYMOUS(DOCTEST_ANON_CLASS_), c, \ + DOCTEST_ANONYMOUS(DOCTEST_ANON_FUNC_), decorators) // for converting types to strings without the header and demangling -#ifdef DOCTEST_CONFIG_WITH_VARIADIC_MACROS -#define DOCTEST_TYPE_TO_STRING_IMPL(...) \ - template <> \ - inline const char* type_to_string<__VA_ARGS__>() { \ - return "<" #__VA_ARGS__ ">"; \ - } -#define DOCTEST_TYPE_TO_STRING(...) \ - namespace doctest \ - { \ - namespace detail \ - { \ - DOCTEST_TYPE_TO_STRING_IMPL(__VA_ARGS__) \ - } \ - } \ - typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_) -#else // DOCTEST_CONFIG_WITH_VARIADIC_MACROS -#define DOCTEST_TYPE_TO_STRING_IMPL(x) \ - template <> \ - inline const char* type_to_string() { \ - return "<" #x ">"; \ - } -#define DOCTEST_TYPE_TO_STRING(x) \ - namespace doctest \ - { \ - namespace detail \ - { \ - DOCTEST_TYPE_TO_STRING_IMPL(x) \ +#define DOCTEST_TYPE_TO_STRING_AS(str, ...) \ + namespace doctest { \ + template <> \ + inline String toString<__VA_ARGS__>() { \ + return str; \ } \ } \ - typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_) -#endif // DOCTEST_CONFIG_WITH_VARIADIC_MACROS + static_assert(true, "") -// for typed tests -#define DOCTEST_TEST_CASE_TEMPLATE_IMPL(decorators, T, types, anon) \ +#define DOCTEST_TYPE_TO_STRING(...) DOCTEST_TYPE_TO_STRING_AS(#__VA_ARGS__, __VA_ARGS__) + +#define DOCTEST_TEST_CASE_TEMPLATE_DEFINE_IMPL(dec, T, iter, func) \ template \ - inline void anon(); \ - struct DOCTEST_CAT(anon, FUNCTOR) \ - { \ - template \ - void operator()() { \ - doctest::detail::regTest( \ - doctest::detail::TestCase(anon, __FILE__, __LINE__, \ - doctest_detail_test_suite_ns::getCurrentTestSuite(), \ - doctest::detail::type_to_string(), Index) * \ - decorators); \ - } \ - }; \ - inline int DOCTEST_CAT(anon, REG_FUNC)() { \ - DOCTEST_CAT(anon, FUNCTOR) registrar; \ - doctest::detail::ForEachType \ - doIt(registrar); \ - return 0; \ + static void func(); \ + namespace { /* NOLINT */ \ + template \ + struct iter; \ + template \ + struct iter> \ + { \ + iter(const char* file, unsigned line, int index) { \ + doctest::detail::regTest(doctest::detail::TestCase(func, file, line, \ + doctest_detail_test_suite_ns::getCurrentTestSuite(), \ + doctest::toString(), \ + int(line) * 1000 + index) \ + * dec); \ + iter>(file, line, index + 1); \ + } \ + }; \ + template <> \ + struct iter> \ + { \ + iter(const char*, unsigned, int) {} \ + }; \ } \ - DOCTEST_GLOBAL_NO_WARNINGS(DOCTEST_CAT(anon, DUMMY)) = DOCTEST_CAT(anon, REG_FUNC)(); \ - DOCTEST_GLOBAL_NO_WARNINGS_END() \ - template \ - inline void anon() - -#ifdef DOCTEST_CONFIG_WITH_VARIADIC_MACROS -#define DOCTEST_TEST_CASE_TEMPLATE(decorators, T, ...) \ - DOCTEST_TEST_CASE_TEMPLATE_IMPL(decorators, T, (__VA_ARGS__), \ - DOCTEST_ANONYMOUS(_DOCTEST_ANON_TMP_)) -#else // DOCTEST_CONFIG_WITH_VARIADIC_MACROS -#define DOCTEST_TEST_CASE_TEMPLATE(decorators, T, types) \ - DOCTEST_TEST_CASE_TEMPLATE_IMPL(decorators, T, types, DOCTEST_ANONYMOUS(_DOCTEST_ANON_TMP_)) -#endif // DOCTEST_CONFIG_WITH_VARIADIC_MACROS - -#define DOCTEST_TEST_CASE_TEMPLATE_DEFINE_IMPL(decorators, T, id, anon) \ template \ - inline void anon(); \ - struct DOCTEST_CAT(id, _FUNCTOR) \ - { \ - int m_line; \ - DOCTEST_CAT(id, _FUNCTOR) \ - (int line) \ - : m_line(line) {} \ - template \ - void operator()() { \ - doctest::detail::regTest( \ - doctest::detail::TestCase(anon, __FILE__, __LINE__, \ - doctest_detail_test_suite_ns::getCurrentTestSuite(), \ - doctest::detail::type_to_string(), \ - m_line * 1000 + Index) * \ - decorators); \ - } \ - }; \ + static void func() + +#define DOCTEST_TEST_CASE_TEMPLATE_DEFINE(dec, T, id) \ + DOCTEST_TEST_CASE_TEMPLATE_DEFINE_IMPL(dec, T, DOCTEST_CAT(id, ITERATOR), \ + DOCTEST_ANONYMOUS(DOCTEST_ANON_TMP_)) + +#define DOCTEST_TEST_CASE_TEMPLATE_INSTANTIATE_IMPL(id, anon, ...) \ + DOCTEST_GLOBAL_NO_WARNINGS(DOCTEST_CAT(anon, DUMMY), /* NOLINT(cert-err58-cpp, fuchsia-statically-constructed-objects) */ \ + doctest::detail::instantiationHelper( \ + DOCTEST_CAT(id, ITERATOR)<__VA_ARGS__>(__FILE__, __LINE__, 0))) + +#define DOCTEST_TEST_CASE_TEMPLATE_INVOKE(id, ...) \ + DOCTEST_TEST_CASE_TEMPLATE_INSTANTIATE_IMPL(id, DOCTEST_ANONYMOUS(DOCTEST_ANON_TMP_), std::tuple<__VA_ARGS__>) \ + static_assert(true, "") + +#define DOCTEST_TEST_CASE_TEMPLATE_APPLY(id, ...) \ + DOCTEST_TEST_CASE_TEMPLATE_INSTANTIATE_IMPL(id, DOCTEST_ANONYMOUS(DOCTEST_ANON_TMP_), __VA_ARGS__) \ + static_assert(true, "") + +#define DOCTEST_TEST_CASE_TEMPLATE_IMPL(dec, T, anon, ...) \ + DOCTEST_TEST_CASE_TEMPLATE_DEFINE_IMPL(dec, T, DOCTEST_CAT(anon, ITERATOR), anon); \ + DOCTEST_TEST_CASE_TEMPLATE_INSTANTIATE_IMPL(anon, anon, std::tuple<__VA_ARGS__>) \ template \ - inline void anon() - -#define DOCTEST_TEST_CASE_TEMPLATE_DEFINE(decorators, T, id) \ - DOCTEST_TEST_CASE_TEMPLATE_DEFINE_IMPL(decorators, T, id, DOCTEST_ANONYMOUS(_DOCTEST_ANON_TMP_)) - -#define DOCTEST_TEST_CASE_TEMPLATE_INSTANTIATE_IMPL(id, types, anon) \ - static int DOCTEST_CAT(anon, REG_FUNC)() { \ - DOCTEST_CAT(id, _FUNCTOR) registrar(__LINE__); \ - doctest::detail::ForEachType \ - doIt(registrar); \ - return 0; \ - } \ - DOCTEST_GLOBAL_NO_WARNINGS(DOCTEST_CAT(anon, DUMMY)) = DOCTEST_CAT(anon, REG_FUNC)(); \ - DOCTEST_GLOBAL_NO_WARNINGS_END() typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_) - -#ifdef DOCTEST_CONFIG_WITH_VARIADIC_MACROS -#define DOCTEST_TEST_CASE_TEMPLATE_INSTANTIATE(id, ...) \ - DOCTEST_TEST_CASE_TEMPLATE_INSTANTIATE_IMPL(id, (__VA_ARGS__), \ - DOCTEST_ANONYMOUS(_DOCTEST_ANON_TMP_)) -#else // DOCTEST_CONFIG_WITH_VARIADIC_MACROS -#define DOCTEST_TEST_CASE_TEMPLATE_INSTANTIATE(id, types) \ - DOCTEST_TEST_CASE_TEMPLATE_INSTANTIATE_IMPL(id, types, DOCTEST_ANONYMOUS(_DOCTEST_ANON_TMP_)) -#endif // DOCTEST_CONFIG_WITH_VARIADIC_MACROS + static void anon() + +#define DOCTEST_TEST_CASE_TEMPLATE(dec, T, ...) \ + DOCTEST_TEST_CASE_TEMPLATE_IMPL(dec, T, DOCTEST_ANONYMOUS(DOCTEST_ANON_TMP_), __VA_ARGS__) // for subcases #define DOCTEST_SUBCASE(name) \ - if(const doctest::detail::Subcase & DOCTEST_ANONYMOUS(_DOCTEST_ANON_SUBCASE_) DOCTEST_UNUSED = \ + if(const doctest::detail::Subcase & DOCTEST_ANONYMOUS(DOCTEST_ANON_SUBCASE_) DOCTEST_UNUSED = \ doctest::detail::Subcase(name, __FILE__, __LINE__)) // for grouping tests in test suites by using code blocks #define DOCTEST_TEST_SUITE_IMPL(decorators, ns_name) \ - namespace ns_name \ - { \ - namespace doctest_detail_test_suite_ns \ - { \ - static DOCTEST_NOINLINE doctest::detail::TestSuite& getCurrentTestSuite() { \ - static doctest::detail::TestSuite data; \ + namespace ns_name { namespace doctest_detail_test_suite_ns { \ + static DOCTEST_NOINLINE doctest::detail::TestSuite& getCurrentTestSuite() noexcept { \ + DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4640) \ + DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wexit-time-destructors") \ + DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH("-Wmissing-field-initializers") \ + static doctest::detail::TestSuite data{}; \ static bool inited = false; \ + DOCTEST_MSVC_SUPPRESS_WARNING_POP \ + DOCTEST_CLANG_SUPPRESS_WARNING_POP \ + DOCTEST_GCC_SUPPRESS_WARNING_POP \ if(!inited) { \ data* decorators; \ inited = true; \ @@ -2270,485 +2260,263 @@ class DOCTEST_INTERFACE Context namespace ns_name #define DOCTEST_TEST_SUITE(decorators) \ - DOCTEST_TEST_SUITE_IMPL(decorators, DOCTEST_ANONYMOUS(_DOCTEST_ANON_SUITE_)) + DOCTEST_TEST_SUITE_IMPL(decorators, DOCTEST_ANONYMOUS(DOCTEST_ANON_SUITE_)) // for starting a testsuite block #define DOCTEST_TEST_SUITE_BEGIN(decorators) \ - DOCTEST_GLOBAL_NO_WARNINGS(DOCTEST_ANONYMOUS(_DOCTEST_ANON_VAR_)) = \ - doctest::detail::setTestSuite(doctest::detail::TestSuite() * decorators); \ - DOCTEST_GLOBAL_NO_WARNINGS_END() \ - typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_) + DOCTEST_GLOBAL_NO_WARNINGS(DOCTEST_ANONYMOUS(DOCTEST_ANON_VAR_), /* NOLINT(cert-err58-cpp) */ \ + doctest::detail::setTestSuite(doctest::detail::TestSuite() * decorators)) \ + static_assert(true, "") // for ending a testsuite block #define DOCTEST_TEST_SUITE_END \ - DOCTEST_GLOBAL_NO_WARNINGS(DOCTEST_ANONYMOUS(_DOCTEST_ANON_VAR_)) = \ - doctest::detail::setTestSuite(doctest::detail::TestSuite() * ""); \ - DOCTEST_GLOBAL_NO_WARNINGS_END() \ - typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_) + DOCTEST_GLOBAL_NO_WARNINGS(DOCTEST_ANONYMOUS(DOCTEST_ANON_VAR_), /* NOLINT(cert-err58-cpp) */ \ + doctest::detail::setTestSuite(doctest::detail::TestSuite() * "")) \ + using DOCTEST_ANONYMOUS(DOCTEST_ANON_FOR_SEMICOLON_) = int // for registering exception translators #define DOCTEST_REGISTER_EXCEPTION_TRANSLATOR_IMPL(translatorName, signature) \ inline doctest::String translatorName(signature); \ - DOCTEST_GLOBAL_NO_WARNINGS(DOCTEST_ANONYMOUS(_DOCTEST_ANON_TRANSLATOR_)) = \ - doctest::registerExceptionTranslator(translatorName); \ - DOCTEST_GLOBAL_NO_WARNINGS_END() \ + DOCTEST_GLOBAL_NO_WARNINGS(DOCTEST_ANONYMOUS(DOCTEST_ANON_TRANSLATOR_), /* NOLINT(cert-err58-cpp) */ \ + doctest::registerExceptionTranslator(translatorName)) \ doctest::String translatorName(signature) #define DOCTEST_REGISTER_EXCEPTION_TRANSLATOR(signature) \ - DOCTEST_REGISTER_EXCEPTION_TRANSLATOR_IMPL(DOCTEST_ANONYMOUS(_DOCTEST_ANON_TRANSLATOR_), \ + DOCTEST_REGISTER_EXCEPTION_TRANSLATOR_IMPL(DOCTEST_ANONYMOUS(DOCTEST_ANON_TRANSLATOR_), \ signature) -// for logging -#define DOCTEST_INFO(x) \ - doctest::detail::ContextScope DOCTEST_ANONYMOUS(_DOCTEST_CAPTURE_)( \ - doctest::detail::ContextBuilder() << x) -#define DOCTEST_CAPTURE(x) DOCTEST_INFO(#x " := " << x) +// for registering reporters +#define DOCTEST_REGISTER_REPORTER(name, priority, reporter) \ + DOCTEST_GLOBAL_NO_WARNINGS(DOCTEST_ANONYMOUS(DOCTEST_ANON_REPORTER_), /* NOLINT(cert-err58-cpp) */ \ + doctest::registerReporter(name, priority, true)) \ + static_assert(true, "") -#define DOCTEST_ADD_AT_IMPL(type, file, line, mb, x) \ - do { \ - doctest::detail::MessageBuilder mb(file, line, doctest::detail::assertType::type); \ - mb << x; \ - if(mb.log()) \ - DOCTEST_BREAK_INTO_DEBUGGER(); \ - mb.react(); \ - } while((void)0, 0) +// for registering listeners +#define DOCTEST_REGISTER_LISTENER(name, priority, reporter) \ + DOCTEST_GLOBAL_NO_WARNINGS(DOCTEST_ANONYMOUS(DOCTEST_ANON_REPORTER_), /* NOLINT(cert-err58-cpp) */ \ + doctest::registerReporter(name, priority, false)) \ + static_assert(true, "") // clang-format off -#define DOCTEST_ADD_MESSAGE_AT(file, line, x) DOCTEST_ADD_AT_IMPL(is_warn, file, line, DOCTEST_ANONYMOUS(_DOCTEST_MESSAGE_), x) -#define DOCTEST_ADD_FAIL_CHECK_AT(file, line, x) DOCTEST_ADD_AT_IMPL(is_check, file, line, DOCTEST_ANONYMOUS(_DOCTEST_MESSAGE_), x) -#define DOCTEST_ADD_FAIL_AT(file, line, x) DOCTEST_ADD_AT_IMPL(is_require, file, line, DOCTEST_ANONYMOUS(_DOCTEST_MESSAGE_), x) +// for logging - disabling formatting because it's important to have these on 2 separate lines - see PR #557 +#define DOCTEST_INFO(...) \ + DOCTEST_INFO_IMPL(DOCTEST_ANONYMOUS(DOCTEST_CAPTURE_), \ + DOCTEST_ANONYMOUS(DOCTEST_CAPTURE_OTHER_), \ + __VA_ARGS__) // clang-format on -#define DOCTEST_MESSAGE(x) DOCTEST_ADD_MESSAGE_AT(__FILE__, __LINE__, x) -#define DOCTEST_FAIL_CHECK(x) DOCTEST_ADD_FAIL_CHECK_AT(__FILE__, __LINE__, x) -#define DOCTEST_FAIL(x) DOCTEST_ADD_FAIL_AT(__FILE__, __LINE__, x) +#define DOCTEST_INFO_IMPL(mb_name, s_name, ...) \ + auto DOCTEST_ANONYMOUS(DOCTEST_CAPTURE_) = doctest::detail::MakeContextScope( \ + [&](std::ostream* s_name) { \ + doctest::detail::MessageBuilder mb_name(__FILE__, __LINE__, doctest::assertType::is_warn); \ + mb_name.m_stream = s_name; \ + mb_name * __VA_ARGS__; \ + }) -#if __cplusplus >= 201402L || (DOCTEST_MSVC >= DOCTEST_COMPILER(19, 10, 0)) -template -constexpr T to_lvalue = x; -#define DOCTEST_TO_LVALUE(...) to_lvalue -#else -#ifdef DOCTEST_CONFIG_WITH_VARIADIC_MACROS -#define DOCTEST_TO_LVALUE(...) TO_LVALUE_CAN_BE_USED_ONLY_IN_CPP14_MODE_OR_WITH_VS_2017_OR_NEWER -#else // DOCTEST_CONFIG_WITH_VARIADIC_MACROS -#define DOCTEST_TO_LVALUE(x) TO_LVALUE_CAN_BE_USED_ONLY_IN_CPP14_MODE_OR_WITH_VS_2017_OR_NEWER -#endif // DOCTEST_CONFIG_WITH_VARIADIC_MACROS -#endif // TO_LVALUE hack for logging macros like INFO() +#define DOCTEST_CAPTURE(x) DOCTEST_INFO(#x " := ", x) -// common code in asserts - for convenience -#define DOCTEST_ASSERT_LOG_AND_REACT(rb) \ - if(rb.log()) \ - DOCTEST_BREAK_INTO_DEBUGGER(); \ - rb.react() - -#ifdef DOCTEST_CONFIG_NO_TRY_CATCH_IN_ASSERTS -#define DOCTEST_WRAP_IN_TRY(x) x; -#else // DOCTEST_CONFIG_NO_TRY_CATCH_IN_ASSERTS -#define DOCTEST_WRAP_IN_TRY(x) \ - try { \ - x; \ - } catch(...) { _DOCTEST_RB.unexpectedExceptionOccurred(); } -#endif // DOCTEST_CONFIG_NO_TRY_CATCH_IN_ASSERTS - -#define DOCTEST_ASSERT_IMPLEMENT_2(expr, assert_type) \ - DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Woverloaded-shift-op-parentheses") \ - doctest::detail::ResultBuilder _DOCTEST_RB( \ - doctest::detail::assertType::assert_type, __FILE__, __LINE__, \ - DOCTEST_TOSTR(DOCTEST_HANDLE_BRACED_VA_ARGS(expr))); \ - DOCTEST_WRAP_IN_TRY(_DOCTEST_RB.setResult( \ - doctest::detail::ExpressionDecomposer(doctest::detail::assertType::assert_type) \ - << DOCTEST_HANDLE_BRACED_VA_ARGS(expr))) \ - DOCTEST_ASSERT_LOG_AND_REACT(_DOCTEST_RB) \ - DOCTEST_CLANG_SUPPRESS_WARNING_POP - -#define DOCTEST_ASSERT_IMPLEMENT_1(expr, assert_type) \ - do { \ - DOCTEST_ASSERT_IMPLEMENT_2(expr, assert_type); \ - } while((void)0, 0) - -#ifdef DOCTEST_CONFIG_WITH_VARIADIC_MACROS -#define DOCTEST_WARN(...) DOCTEST_ASSERT_IMPLEMENT_1((__VA_ARGS__), DT_WARN) -#define DOCTEST_CHECK(...) DOCTEST_ASSERT_IMPLEMENT_1((__VA_ARGS__), DT_CHECK) -#define DOCTEST_REQUIRE(...) DOCTEST_ASSERT_IMPLEMENT_1((__VA_ARGS__), DT_REQUIRE) -#define DOCTEST_WARN_FALSE(...) DOCTEST_ASSERT_IMPLEMENT_1((__VA_ARGS__), DT_WARN_FALSE) -#define DOCTEST_CHECK_FALSE(...) DOCTEST_ASSERT_IMPLEMENT_1((__VA_ARGS__), DT_CHECK_FALSE) -#define DOCTEST_REQUIRE_FALSE(...) DOCTEST_ASSERT_IMPLEMENT_1((__VA_ARGS__), DT_REQUIRE_FALSE) -#else // DOCTEST_CONFIG_WITH_VARIADIC_MACROS -#define DOCTEST_WARN(expr) DOCTEST_ASSERT_IMPLEMENT_1(expr, DT_WARN) -#define DOCTEST_CHECK(expr) DOCTEST_ASSERT_IMPLEMENT_1(expr, DT_CHECK) -#define DOCTEST_REQUIRE(expr) DOCTEST_ASSERT_IMPLEMENT_1(expr, DT_REQUIRE) -#define DOCTEST_WARN_FALSE(expr) DOCTEST_ASSERT_IMPLEMENT_1(expr, DT_WARN_FALSE) -#define DOCTEST_CHECK_FALSE(expr) DOCTEST_ASSERT_IMPLEMENT_1(expr, DT_CHECK_FALSE) -#define DOCTEST_REQUIRE_FALSE(expr) DOCTEST_ASSERT_IMPLEMENT_1(expr, DT_REQUIRE_FALSE) -#endif // DOCTEST_CONFIG_WITH_VARIADIC_MACROS +#define DOCTEST_ADD_AT_IMPL(type, file, line, mb, ...) \ + DOCTEST_FUNC_SCOPE_BEGIN { \ + doctest::detail::MessageBuilder mb(file, line, doctest::assertType::type); \ + mb * __VA_ARGS__; \ + if(mb.log()) \ + DOCTEST_BREAK_INTO_DEBUGGER(); \ + mb.react(); \ + } DOCTEST_FUNC_SCOPE_END // clang-format off -#ifdef DOCTEST_CONFIG_WITH_VARIADIC_MACROS -#define DOCTEST_WARN_MESSAGE(cond, msg) do { DOCTEST_INFO(msg); DOCTEST_ASSERT_IMPLEMENT_2((cond), DT_WARN); } while((void)0, 0) -#define DOCTEST_CHECK_MESSAGE(cond, msg) do { DOCTEST_INFO(msg); DOCTEST_ASSERT_IMPLEMENT_2((cond), DT_CHECK); } while((void)0, 0) -#define DOCTEST_REQUIRE_MESSAGE(cond, msg) do { DOCTEST_INFO(msg); DOCTEST_ASSERT_IMPLEMENT_2((cond), DT_REQUIRE); } while((void)0, 0) -#define DOCTEST_WARN_FALSE_MESSAGE(cond, msg) do { DOCTEST_INFO(msg); DOCTEST_ASSERT_IMPLEMENT_2((cond), DT_WARN_FALSE); } while((void)0, 0) -#define DOCTEST_CHECK_FALSE_MESSAGE(cond, msg) do { DOCTEST_INFO(msg); DOCTEST_ASSERT_IMPLEMENT_2((cond), DT_CHECK_FALSE); } while((void)0, 0) -#define DOCTEST_REQUIRE_FALSE_MESSAGE(cond, msg) do { DOCTEST_INFO(msg); DOCTEST_ASSERT_IMPLEMENT_2((cond), DT_REQUIRE_FALSE); } while((void)0, 0) -#else // DOCTEST_CONFIG_WITH_VARIADIC_MACROS -#define DOCTEST_WARN_MESSAGE(cond, msg) do { DOCTEST_INFO(msg); DOCTEST_ASSERT_IMPLEMENT_2(cond, DT_WARN); } while((void)0, 0) -#define DOCTEST_CHECK_MESSAGE(cond, msg) do { DOCTEST_INFO(msg); DOCTEST_ASSERT_IMPLEMENT_2(cond, DT_CHECK); } while((void)0, 0) -#define DOCTEST_REQUIRE_MESSAGE(cond, msg) do { DOCTEST_INFO(msg); DOCTEST_ASSERT_IMPLEMENT_2(cond, DT_REQUIRE); } while((void)0, 0) -#define DOCTEST_WARN_FALSE_MESSAGE(cond, msg) do { DOCTEST_INFO(msg); DOCTEST_ASSERT_IMPLEMENT_2(cond, DT_WARN_FALSE); } while((void)0, 0) -#define DOCTEST_CHECK_FALSE_MESSAGE(cond, msg) do { DOCTEST_INFO(msg); DOCTEST_ASSERT_IMPLEMENT_2(cond, DT_CHECK_FALSE); } while((void)0, 0) -#define DOCTEST_REQUIRE_FALSE_MESSAGE(cond, msg) do { DOCTEST_INFO(msg); DOCTEST_ASSERT_IMPLEMENT_2(cond, DT_REQUIRE_FALSE); } while((void)0, 0) -#endif // DOCTEST_CONFIG_WITH_VARIADIC_MACROS +#define DOCTEST_ADD_MESSAGE_AT(file, line, ...) DOCTEST_ADD_AT_IMPL(is_warn, file, line, DOCTEST_ANONYMOUS(DOCTEST_MESSAGE_), __VA_ARGS__) +#define DOCTEST_ADD_FAIL_CHECK_AT(file, line, ...) DOCTEST_ADD_AT_IMPL(is_check, file, line, DOCTEST_ANONYMOUS(DOCTEST_MESSAGE_), __VA_ARGS__) +#define DOCTEST_ADD_FAIL_AT(file, line, ...) DOCTEST_ADD_AT_IMPL(is_require, file, line, DOCTEST_ANONYMOUS(DOCTEST_MESSAGE_), __VA_ARGS__) // clang-format on -#define DOCTEST_ASSERT_THROWS(expr, assert_type) \ - do { \ - if(!doctest::detail::getTestsContextState()->no_throw) { \ - doctest::detail::ResultBuilder _DOCTEST_RB(doctest::detail::assertType::assert_type, \ - __FILE__, __LINE__, #expr); \ - try { \ - expr; \ - } catch(...) { _DOCTEST_RB.m_threw = true; } \ - DOCTEST_ASSERT_LOG_AND_REACT(_DOCTEST_RB); \ - } \ - } while((void)0, 0) - -#define DOCTEST_ASSERT_THROWS_AS(expr, as, assert_type) \ - do { \ - if(!doctest::detail::getTestsContextState()->no_throw) { \ - doctest::detail::ResultBuilder _DOCTEST_RB( \ - doctest::detail::assertType::assert_type, __FILE__, __LINE__, #expr, \ - DOCTEST_TOSTR(DOCTEST_HANDLE_BRACED_VA_ARGS(as))); \ - try { \ - expr; \ - } catch(const DOCTEST_HANDLE_BRACED_VA_ARGS(as)&) { \ - _DOCTEST_RB.m_threw = true; \ - _DOCTEST_RB.m_threw_as = true; \ - } catch(...) { _DOCTEST_RB.unexpectedExceptionOccurred(); } \ - DOCTEST_ASSERT_LOG_AND_REACT(_DOCTEST_RB); \ - } \ - } while((void)0, 0) - -#define DOCTEST_ASSERT_NOTHROW(expr, assert_type) \ - do { \ - if(!doctest::detail::getTestsContextState()->no_throw) { \ - doctest::detail::ResultBuilder _DOCTEST_RB(doctest::detail::assertType::assert_type, \ - __FILE__, __LINE__, #expr); \ - try { \ - expr; \ - } catch(...) { _DOCTEST_RB.unexpectedExceptionOccurred(); } \ - DOCTEST_ASSERT_LOG_AND_REACT(_DOCTEST_RB); \ - } \ - } while((void)0, 0) +#define DOCTEST_MESSAGE(...) DOCTEST_ADD_MESSAGE_AT(__FILE__, __LINE__, __VA_ARGS__) +#define DOCTEST_FAIL_CHECK(...) DOCTEST_ADD_FAIL_CHECK_AT(__FILE__, __LINE__, __VA_ARGS__) +#define DOCTEST_FAIL(...) DOCTEST_ADD_FAIL_AT(__FILE__, __LINE__, __VA_ARGS__) -#define DOCTEST_WARN_THROWS(expr) DOCTEST_ASSERT_THROWS(expr, DT_WARN_THROWS) -#define DOCTEST_CHECK_THROWS(expr) DOCTEST_ASSERT_THROWS(expr, DT_CHECK_THROWS) -#define DOCTEST_REQUIRE_THROWS(expr) DOCTEST_ASSERT_THROWS(expr, DT_REQUIRE_THROWS) +#define DOCTEST_TO_LVALUE(...) __VA_ARGS__ // Not removed to keep backwards compatibility. -// clang-format off -#ifdef DOCTEST_CONFIG_WITH_VARIADIC_MACROS -#define DOCTEST_WARN_THROWS_AS(expr, ...) DOCTEST_ASSERT_THROWS_AS(expr, (__VA_ARGS__), DT_WARN_THROWS_AS) -#define DOCTEST_CHECK_THROWS_AS(expr, ...) DOCTEST_ASSERT_THROWS_AS(expr, (__VA_ARGS__), DT_CHECK_THROWS_AS) -#define DOCTEST_REQUIRE_THROWS_AS(expr, ...) DOCTEST_ASSERT_THROWS_AS(expr, (__VA_ARGS__), DT_REQUIRE_THROWS_AS) -#else // DOCTEST_CONFIG_WITH_VARIADIC_MACROS -#define DOCTEST_WARN_THROWS_AS(expr, ex) DOCTEST_ASSERT_THROWS_AS(expr, ex, DT_WARN_THROWS_AS) -#define DOCTEST_CHECK_THROWS_AS(expr, ex) DOCTEST_ASSERT_THROWS_AS(expr, ex, DT_CHECK_THROWS_AS) -#define DOCTEST_REQUIRE_THROWS_AS(expr, ex) DOCTEST_ASSERT_THROWS_AS(expr, ex, DT_REQUIRE_THROWS_AS) -#endif // DOCTEST_CONFIG_WITH_VARIADIC_MACROS -// clang-format on +#ifndef DOCTEST_CONFIG_SUPER_FAST_ASSERTS -#define DOCTEST_WARN_NOTHROW(expr) DOCTEST_ASSERT_NOTHROW(expr, DT_WARN_NOTHROW) -#define DOCTEST_CHECK_NOTHROW(expr) DOCTEST_ASSERT_NOTHROW(expr, DT_CHECK_NOTHROW) -#define DOCTEST_REQUIRE_NOTHROW(expr) DOCTEST_ASSERT_NOTHROW(expr, DT_REQUIRE_NOTHROW) +#define DOCTEST_ASSERT_IMPLEMENT_2(assert_type, ...) \ + DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Woverloaded-shift-op-parentheses") \ + /* NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks) */ \ + doctest::detail::ResultBuilder DOCTEST_RB(doctest::assertType::assert_type, __FILE__, \ + __LINE__, #__VA_ARGS__); \ + DOCTEST_WRAP_IN_TRY(DOCTEST_RB.setResult( \ + doctest::detail::ExpressionDecomposer(doctest::assertType::assert_type) \ + << __VA_ARGS__)) /* NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks) */ \ + DOCTEST_ASSERT_LOG_REACT_RETURN(DOCTEST_RB) \ + DOCTEST_CLANG_SUPPRESS_WARNING_POP -// clang-format off -#define DOCTEST_WARN_THROWS_MESSAGE(expr, msg) do { DOCTEST_INFO(msg); DOCTEST_WARN_THROWS(expr); } while((void)0, 0) -#define DOCTEST_CHECK_THROWS_MESSAGE(expr, msg) do { DOCTEST_INFO(msg); DOCTEST_CHECK_THROWS(expr); } while((void)0, 0) -#define DOCTEST_REQUIRE_THROWS_MESSAGE(expr, msg) do { DOCTEST_INFO(msg); DOCTEST_REQUIRE_THROWS(expr); } while((void)0, 0) -#define DOCTEST_WARN_THROWS_AS_MESSAGE(expr, ex, msg) do { DOCTEST_INFO(msg); DOCTEST_WARN_THROWS_AS(expr, ex); } while((void)0, 0) -#define DOCTEST_CHECK_THROWS_AS_MESSAGE(expr, ex, msg) do { DOCTEST_INFO(msg); DOCTEST_CHECK_THROWS_AS(expr, ex); } while((void)0, 0) -#define DOCTEST_REQUIRE_THROWS_AS_MESSAGE(expr, ex, msg) do { DOCTEST_INFO(msg); DOCTEST_REQUIRE_THROWS_AS(expr, ex); } while((void)0, 0) -#define DOCTEST_WARN_NOTHROW_MESSAGE(expr, msg) do { DOCTEST_INFO(msg); DOCTEST_WARN_NOTHROW(expr); } while((void)0, 0) -#define DOCTEST_CHECK_NOTHROW_MESSAGE(expr, msg) do { DOCTEST_INFO(msg); DOCTEST_CHECK_NOTHROW(expr); } while((void)0, 0) -#define DOCTEST_REQUIRE_NOTHROW_MESSAGE(expr, msg) do { DOCTEST_INFO(msg); DOCTEST_REQUIRE_NOTHROW(expr); } while((void)0, 0) -// clang-format on +#define DOCTEST_ASSERT_IMPLEMENT_1(assert_type, ...) \ + DOCTEST_FUNC_SCOPE_BEGIN { \ + DOCTEST_ASSERT_IMPLEMENT_2(assert_type, __VA_ARGS__); \ + } DOCTEST_FUNC_SCOPE_END // NOLINT(clang-analyzer-cplusplus.NewDeleteLeaks) -#ifdef DOCTEST_CONFIG_WITH_VARIADIC_MACROS -#define DOCTEST_BINARY_ASSERT(assert_type, expr, comp) \ - do { \ - doctest::detail::ResultBuilder _DOCTEST_RB( \ - doctest::detail::assertType::assert_type, __FILE__, __LINE__, \ - DOCTEST_TOSTR(DOCTEST_HANDLE_BRACED_VA_ARGS(expr))); \ - DOCTEST_WRAP_IN_TRY( \ - _DOCTEST_RB.binary_assert( \ - DOCTEST_HANDLE_BRACED_VA_ARGS(expr))) \ - DOCTEST_ASSERT_LOG_AND_REACT(_DOCTEST_RB); \ - } while((void)0, 0) -#else // DOCTEST_CONFIG_WITH_VARIADIC_MACROS -#define DOCTEST_BINARY_ASSERT(assert_type, lhs, rhs, comp) \ - do { \ - doctest::detail::ResultBuilder _DOCTEST_RB(doctest::detail::assertType::assert_type, \ - __FILE__, __LINE__, #lhs ", " #rhs); \ +#define DOCTEST_BINARY_ASSERT(assert_type, comp, ...) \ + DOCTEST_FUNC_SCOPE_BEGIN { \ + doctest::detail::ResultBuilder DOCTEST_RB(doctest::assertType::assert_type, __FILE__, \ + __LINE__, #__VA_ARGS__); \ DOCTEST_WRAP_IN_TRY( \ - _DOCTEST_RB.binary_assert(lhs, \ - rhs)) \ - DOCTEST_ASSERT_LOG_AND_REACT(_DOCTEST_RB); \ - } while((void)0, 0) -#endif // DOCTEST_CONFIG_WITH_VARIADIC_MACROS - -#define DOCTEST_UNARY_ASSERT(assert_type, expr) \ - do { \ - doctest::detail::ResultBuilder _DOCTEST_RB( \ - doctest::detail::assertType::assert_type, __FILE__, __LINE__, \ - DOCTEST_TOSTR(DOCTEST_HANDLE_BRACED_VA_ARGS(expr))); \ - DOCTEST_WRAP_IN_TRY(_DOCTEST_RB.unary_assert(DOCTEST_HANDLE_BRACED_VA_ARGS(expr))) \ - DOCTEST_ASSERT_LOG_AND_REACT(_DOCTEST_RB); \ - } while((void)0, 0) - -#ifdef DOCTEST_CONFIG_WITH_VARIADIC_MACROS -#define DOCTEST_WARN_EQ(...) DOCTEST_BINARY_ASSERT(DT_WARN_EQ, (__VA_ARGS__), eq) -#define DOCTEST_CHECK_EQ(...) DOCTEST_BINARY_ASSERT(DT_CHECK_EQ, (__VA_ARGS__), eq) -#define DOCTEST_REQUIRE_EQ(...) DOCTEST_BINARY_ASSERT(DT_REQUIRE_EQ, (__VA_ARGS__), eq) -#define DOCTEST_WARN_NE(...) DOCTEST_BINARY_ASSERT(DT_WARN_NE, (__VA_ARGS__), ne) -#define DOCTEST_CHECK_NE(...) DOCTEST_BINARY_ASSERT(DT_CHECK_NE, (__VA_ARGS__), ne) -#define DOCTEST_REQUIRE_NE(...) DOCTEST_BINARY_ASSERT(DT_REQUIRE_NE, (__VA_ARGS__), ne) -#define DOCTEST_WARN_GT(...) DOCTEST_BINARY_ASSERT(DT_WARN_GT, (__VA_ARGS__), gt) -#define DOCTEST_CHECK_GT(...) DOCTEST_BINARY_ASSERT(DT_CHECK_GT, (__VA_ARGS__), gt) -#define DOCTEST_REQUIRE_GT(...) DOCTEST_BINARY_ASSERT(DT_REQUIRE_GT, (__VA_ARGS__), gt) -#define DOCTEST_WARN_LT(...) DOCTEST_BINARY_ASSERT(DT_WARN_LT, (__VA_ARGS__), lt) -#define DOCTEST_CHECK_LT(...) DOCTEST_BINARY_ASSERT(DT_CHECK_LT, (__VA_ARGS__), lt) -#define DOCTEST_REQUIRE_LT(...) DOCTEST_BINARY_ASSERT(DT_REQUIRE_LT, (__VA_ARGS__), lt) -#define DOCTEST_WARN_GE(...) DOCTEST_BINARY_ASSERT(DT_WARN_GE, (__VA_ARGS__), ge) -#define DOCTEST_CHECK_GE(...) DOCTEST_BINARY_ASSERT(DT_CHECK_GE, (__VA_ARGS__), ge) -#define DOCTEST_REQUIRE_GE(...) DOCTEST_BINARY_ASSERT(DT_REQUIRE_GE, (__VA_ARGS__), ge) -#define DOCTEST_WARN_LE(...) DOCTEST_BINARY_ASSERT(DT_WARN_LE, (__VA_ARGS__), le) -#define DOCTEST_CHECK_LE(...) DOCTEST_BINARY_ASSERT(DT_CHECK_LE, (__VA_ARGS__), le) -#define DOCTEST_REQUIRE_LE(...) DOCTEST_BINARY_ASSERT(DT_REQUIRE_LE, (__VA_ARGS__), le) - -#define DOCTEST_WARN_UNARY(...) DOCTEST_UNARY_ASSERT(DT_WARN_UNARY, (__VA_ARGS__)) -#define DOCTEST_CHECK_UNARY(...) DOCTEST_UNARY_ASSERT(DT_CHECK_UNARY, (__VA_ARGS__)) -#define DOCTEST_REQUIRE_UNARY(...) DOCTEST_UNARY_ASSERT(DT_REQUIRE_UNARY, (__VA_ARGS__)) -#define DOCTEST_WARN_UNARY_FALSE(...) DOCTEST_UNARY_ASSERT(DT_WARN_UNARY_FALSE, (__VA_ARGS__)) -#define DOCTEST_CHECK_UNARY_FALSE(...) DOCTEST_UNARY_ASSERT(DT_CHECK_UNARY_FALSE, (__VA_ARGS__)) -#define DOCTEST_REQUIRE_UNARY_FALSE(...) DOCTEST_UNARY_ASSERT(DT_REQUIRE_UNARY_FALSE, (__VA_ARGS__)) -#else // DOCTEST_CONFIG_WITH_VARIADIC_MACROS -#define DOCTEST_WARN_EQ(lhs, rhs) DOCTEST_BINARY_ASSERT(DT_WARN_EQ, lhs, rhs, eq) -#define DOCTEST_CHECK_EQ(lhs, rhs) DOCTEST_BINARY_ASSERT(DT_CHECK_EQ, lhs, rhs, eq) -#define DOCTEST_REQUIRE_EQ(lhs, rhs) DOCTEST_BINARY_ASSERT(DT_REQUIRE_EQ, lhs, rhs, eq) -#define DOCTEST_WARN_NE(lhs, rhs) DOCTEST_BINARY_ASSERT(DT_WARN_NE, lhs, rhs, ne) -#define DOCTEST_CHECK_NE(lhs, rhs) DOCTEST_BINARY_ASSERT(DT_CHECK_NE, lhs, rhs, ne) -#define DOCTEST_REQUIRE_NE(lhs, rhs) DOCTEST_BINARY_ASSERT(DT_REQUIRE_NE, lhs, rhs, ne) -#define DOCTEST_WARN_GT(lhs, rhs) DOCTEST_BINARY_ASSERT(DT_WARN_GT, lhs, rhs, gt) -#define DOCTEST_CHECK_GT(lhs, rhs) DOCTEST_BINARY_ASSERT(DT_CHECK_GT, lhs, rhs, gt) -#define DOCTEST_REQUIRE_GT(lhs, rhs) DOCTEST_BINARY_ASSERT(DT_REQUIRE_GT, lhs, rhs, gt) -#define DOCTEST_WARN_LT(lhs, rhs) DOCTEST_BINARY_ASSERT(DT_WARN_LT, lhs, rhs, lt) -#define DOCTEST_CHECK_LT(lhs, rhs) DOCTEST_BINARY_ASSERT(DT_CHECK_LT, lhs, rhs, lt) -#define DOCTEST_REQUIRE_LT(lhs, rhs) DOCTEST_BINARY_ASSERT(DT_REQUIRE_LT, lhs, rhs, lt) -#define DOCTEST_WARN_GE(lhs, rhs) DOCTEST_BINARY_ASSERT(DT_WARN_GE, lhs, rhs, ge) -#define DOCTEST_CHECK_GE(lhs, rhs) DOCTEST_BINARY_ASSERT(DT_CHECK_GE, lhs, rhs, ge) -#define DOCTEST_REQUIRE_GE(lhs, rhs) DOCTEST_BINARY_ASSERT(DT_REQUIRE_GE, lhs, rhs, ge) -#define DOCTEST_WARN_LE(lhs, rhs) DOCTEST_BINARY_ASSERT(DT_WARN_LE, lhs, rhs, le) -#define DOCTEST_CHECK_LE(lhs, rhs) DOCTEST_BINARY_ASSERT(DT_CHECK_LE, lhs, rhs, le) -#define DOCTEST_REQUIRE_LE(lhs, rhs) DOCTEST_BINARY_ASSERT(DT_REQUIRE_LE, lhs, rhs, le) - -#define DOCTEST_WARN_UNARY(v) DOCTEST_UNARY_ASSERT(DT_WARN_UNARY, v) -#define DOCTEST_CHECK_UNARY(v) DOCTEST_UNARY_ASSERT(DT_CHECK_UNARY, v) -#define DOCTEST_REQUIRE_UNARY(v) DOCTEST_UNARY_ASSERT(DT_REQUIRE_UNARY, v) -#define DOCTEST_WARN_UNARY_FALSE(v) DOCTEST_UNARY_ASSERT(DT_WARN_UNARY_FALSE, v) -#define DOCTEST_CHECK_UNARY_FALSE(v) DOCTEST_UNARY_ASSERT(DT_CHECK_UNARY_FALSE, v) -#define DOCTEST_REQUIRE_UNARY_FALSE(v) DOCTEST_UNARY_ASSERT(DT_REQUIRE_UNARY_FALSE, v) -#endif // DOCTEST_CONFIG_WITH_VARIADIC_MACROS + DOCTEST_RB.binary_assert( \ + __VA_ARGS__)) \ + DOCTEST_ASSERT_LOG_REACT_RETURN(DOCTEST_RB); \ + } DOCTEST_FUNC_SCOPE_END + +#define DOCTEST_UNARY_ASSERT(assert_type, ...) \ + DOCTEST_FUNC_SCOPE_BEGIN { \ + doctest::detail::ResultBuilder DOCTEST_RB(doctest::assertType::assert_type, __FILE__, \ + __LINE__, #__VA_ARGS__); \ + DOCTEST_WRAP_IN_TRY(DOCTEST_RB.unary_assert(__VA_ARGS__)) \ + DOCTEST_ASSERT_LOG_REACT_RETURN(DOCTEST_RB); \ + } DOCTEST_FUNC_SCOPE_END -#ifndef DOCTEST_CONFIG_SUPER_FAST_ASSERTS +#else // DOCTEST_CONFIG_SUPER_FAST_ASSERTS -#ifdef DOCTEST_CONFIG_WITH_VARIADIC_MACROS -#define DOCTEST_FAST_BINARY_ASSERT(assert_type, expr, comparison) \ - do { \ - int _DOCTEST_FAST_RES = doctest::detail::fast_binary_assert< \ - doctest::detail::binaryAssertComparison::comparison>( \ - doctest::detail::assertType::assert_type, __FILE__, __LINE__, \ - DOCTEST_TOSTR(DOCTEST_HANDLE_BRACED_VA_ARGS(expr)), \ - DOCTEST_HANDLE_BRACED_VA_ARGS(expr)); \ - if(_DOCTEST_FAST_RES & doctest::detail::assertAction::dbgbreak) \ - DOCTEST_BREAK_INTO_DEBUGGER(); \ - doctest::detail::fastAssertThrowIfFlagSet(_DOCTEST_FAST_RES); \ - } while((void)0, 0) -#else // DOCTEST_CONFIG_WITH_VARIADIC_MACROS -#define DOCTEST_FAST_BINARY_ASSERT(assert_type, lhs, rhs, comparison) \ - do { \ - int _DOCTEST_FAST_RES = doctest::detail::fast_binary_assert< \ - doctest::detail::binaryAssertComparison::comparison>( \ - doctest::detail::assertType::assert_type, __FILE__, __LINE__, #lhs ", " #rhs, lhs, \ - rhs); \ - if(_DOCTEST_FAST_RES & doctest::detail::assertAction::dbgbreak) \ - DOCTEST_BREAK_INTO_DEBUGGER(); \ - doctest::detail::fastAssertThrowIfFlagSet(_DOCTEST_FAST_RES); \ - } while((void)0, 0) -#endif // DOCTEST_CONFIG_WITH_VARIADIC_MACROS +// necessary for _MESSAGE +#define DOCTEST_ASSERT_IMPLEMENT_2 DOCTEST_ASSERT_IMPLEMENT_1 -#define DOCTEST_FAST_UNARY_ASSERT(assert_type, expr) \ - do { \ - int _DOCTEST_FAST_RES = doctest::detail::fast_unary_assert( \ - doctest::detail::assertType::assert_type, __FILE__, __LINE__, \ - DOCTEST_TOSTR(DOCTEST_HANDLE_BRACED_VA_ARGS(expr)), \ - DOCTEST_HANDLE_BRACED_VA_ARGS(expr)); \ - if(_DOCTEST_FAST_RES & doctest::detail::assertAction::dbgbreak) \ - DOCTEST_BREAK_INTO_DEBUGGER(); \ - doctest::detail::fastAssertThrowIfFlagSet(_DOCTEST_FAST_RES); \ - } while((void)0, 0) +#define DOCTEST_ASSERT_IMPLEMENT_1(assert_type, ...) \ + DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Woverloaded-shift-op-parentheses") \ + doctest::detail::decomp_assert( \ + doctest::assertType::assert_type, __FILE__, __LINE__, #__VA_ARGS__, \ + doctest::detail::ExpressionDecomposer(doctest::assertType::assert_type) \ + << __VA_ARGS__) DOCTEST_CLANG_SUPPRESS_WARNING_POP -#else // DOCTEST_CONFIG_SUPER_FAST_ASSERTS +#define DOCTEST_BINARY_ASSERT(assert_type, comparison, ...) \ + doctest::detail::binary_assert( \ + doctest::assertType::assert_type, __FILE__, __LINE__, #__VA_ARGS__, __VA_ARGS__) -#ifdef DOCTEST_CONFIG_WITH_VARIADIC_MACROS -#define DOCTEST_FAST_BINARY_ASSERT(assert_type, expr, comparison) \ - doctest::detail::fast_binary_assert( \ - doctest::detail::assertType::assert_type, __FILE__, __LINE__, \ - DOCTEST_TOSTR(DOCTEST_HANDLE_BRACED_VA_ARGS(expr)), \ - DOCTEST_HANDLE_BRACED_VA_ARGS(expr)) -#else // DOCTEST_CONFIG_WITH_VARIADIC_MACROS -#define DOCTEST_FAST_BINARY_ASSERT(assert_type, lhs, rhs, comparison) \ - doctest::detail::fast_binary_assert( \ - doctest::detail::assertType::assert_type, __FILE__, __LINE__, #lhs ", " #rhs, lhs, \ - rhs) -#endif // DOCTEST_CONFIG_WITH_VARIADIC_MACROS - -#define DOCTEST_FAST_UNARY_ASSERT(assert_type, expr) \ - doctest::detail::fast_unary_assert(doctest::detail::assertType::assert_type, __FILE__, \ - __LINE__, \ - DOCTEST_TOSTR(DOCTEST_HANDLE_BRACED_VA_ARGS(expr)), \ - DOCTEST_HANDLE_BRACED_VA_ARGS(expr)) +#define DOCTEST_UNARY_ASSERT(assert_type, ...) \ + doctest::detail::unary_assert(doctest::assertType::assert_type, __FILE__, __LINE__, \ + #__VA_ARGS__, __VA_ARGS__) #endif // DOCTEST_CONFIG_SUPER_FAST_ASSERTS +#define DOCTEST_WARN(...) DOCTEST_ASSERT_IMPLEMENT_1(DT_WARN, __VA_ARGS__) +#define DOCTEST_CHECK(...) DOCTEST_ASSERT_IMPLEMENT_1(DT_CHECK, __VA_ARGS__) +#define DOCTEST_REQUIRE(...) DOCTEST_ASSERT_IMPLEMENT_1(DT_REQUIRE, __VA_ARGS__) +#define DOCTEST_WARN_FALSE(...) DOCTEST_ASSERT_IMPLEMENT_1(DT_WARN_FALSE, __VA_ARGS__) +#define DOCTEST_CHECK_FALSE(...) DOCTEST_ASSERT_IMPLEMENT_1(DT_CHECK_FALSE, __VA_ARGS__) +#define DOCTEST_REQUIRE_FALSE(...) DOCTEST_ASSERT_IMPLEMENT_1(DT_REQUIRE_FALSE, __VA_ARGS__) + // clang-format off -#ifdef DOCTEST_CONFIG_WITH_VARIADIC_MACROS -#define DOCTEST_FAST_WARN_EQ(...) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_WARN_EQ, (__VA_ARGS__), eq) -#define DOCTEST_FAST_CHECK_EQ(...) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_CHECK_EQ, (__VA_ARGS__), eq) -#define DOCTEST_FAST_REQUIRE_EQ(...) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_REQUIRE_EQ, (__VA_ARGS__), eq) -#define DOCTEST_FAST_WARN_NE(...) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_WARN_NE, (__VA_ARGS__), ne) -#define DOCTEST_FAST_CHECK_NE(...) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_CHECK_NE, (__VA_ARGS__), ne) -#define DOCTEST_FAST_REQUIRE_NE(...) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_REQUIRE_NE, (__VA_ARGS__), ne) -#define DOCTEST_FAST_WARN_GT(...) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_WARN_GT, (__VA_ARGS__), gt) -#define DOCTEST_FAST_CHECK_GT(...) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_CHECK_GT, (__VA_ARGS__), gt) -#define DOCTEST_FAST_REQUIRE_GT(...) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_REQUIRE_GT, (__VA_ARGS__), gt) -#define DOCTEST_FAST_WARN_LT(...) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_WARN_LT, (__VA_ARGS__), lt) -#define DOCTEST_FAST_CHECK_LT(...) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_CHECK_LT, (__VA_ARGS__), lt) -#define DOCTEST_FAST_REQUIRE_LT(...) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_REQUIRE_LT, (__VA_ARGS__), lt) -#define DOCTEST_FAST_WARN_GE(...) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_WARN_GE, (__VA_ARGS__), ge) -#define DOCTEST_FAST_CHECK_GE(...) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_CHECK_GE, (__VA_ARGS__), ge) -#define DOCTEST_FAST_REQUIRE_GE(...) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_REQUIRE_GE, (__VA_ARGS__), ge) -#define DOCTEST_FAST_WARN_LE(...) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_WARN_LE, (__VA_ARGS__), le) -#define DOCTEST_FAST_CHECK_LE(...) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_CHECK_LE, (__VA_ARGS__), le) -#define DOCTEST_FAST_REQUIRE_LE(...) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_REQUIRE_LE, (__VA_ARGS__), le) - -#define DOCTEST_FAST_WARN_UNARY(...) DOCTEST_FAST_UNARY_ASSERT(DT_FAST_WARN_UNARY, (__VA_ARGS__)) -#define DOCTEST_FAST_CHECK_UNARY(...) DOCTEST_FAST_UNARY_ASSERT(DT_FAST_CHECK_UNARY, (__VA_ARGS__)) -#define DOCTEST_FAST_REQUIRE_UNARY(...) DOCTEST_FAST_UNARY_ASSERT(DT_FAST_REQUIRE_UNARY, (__VA_ARGS__)) -#define DOCTEST_FAST_WARN_UNARY_FALSE(...) DOCTEST_FAST_UNARY_ASSERT(DT_FAST_WARN_UNARY_FALSE, (__VA_ARGS__)) -#define DOCTEST_FAST_CHECK_UNARY_FALSE(...) DOCTEST_FAST_UNARY_ASSERT(DT_FAST_CHECK_UNARY_FALSE, (__VA_ARGS__)) -#define DOCTEST_FAST_REQUIRE_UNARY_FALSE(...) DOCTEST_FAST_UNARY_ASSERT(DT_FAST_REQUIRE_UNARY_FALSE, (__VA_ARGS__)) -#else // DOCTEST_CONFIG_WITH_VARIADIC_MACROS -#define DOCTEST_FAST_WARN_EQ(l, r) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_WARN_EQ, l, r, eq) -#define DOCTEST_FAST_CHECK_EQ(l, r) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_CHECK_EQ, l, r, eq) -#define DOCTEST_FAST_REQUIRE_EQ(l, r) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_REQUIRE_EQ, l, r, eq) -#define DOCTEST_FAST_WARN_NE(l, r) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_WARN_NE, l, r, ne) -#define DOCTEST_FAST_CHECK_NE(l, r) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_CHECK_NE, l, r, ne) -#define DOCTEST_FAST_REQUIRE_NE(l, r) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_REQUIRE_NE, l, r, ne) -#define DOCTEST_FAST_WARN_GT(l, r) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_WARN_GT, l, r, gt) -#define DOCTEST_FAST_CHECK_GT(l, r) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_CHECK_GT, l, r, gt) -#define DOCTEST_FAST_REQUIRE_GT(l, r) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_REQUIRE_GT, l, r, gt) -#define DOCTEST_FAST_WARN_LT(l, r) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_WARN_LT, l, r, lt) -#define DOCTEST_FAST_CHECK_LT(l, r) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_CHECK_LT, l, r, lt) -#define DOCTEST_FAST_REQUIRE_LT(l, r) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_REQUIRE_LT, l, r, lt) -#define DOCTEST_FAST_WARN_GE(l, r) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_WARN_GE, l, r, ge) -#define DOCTEST_FAST_CHECK_GE(l, r) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_CHECK_GE, l, r, ge) -#define DOCTEST_FAST_REQUIRE_GE(l, r) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_REQUIRE_GE, l, r, ge) -#define DOCTEST_FAST_WARN_LE(l, r) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_WARN_LE, l, r, le) -#define DOCTEST_FAST_CHECK_LE(l, r) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_CHECK_LE, l, r, le) -#define DOCTEST_FAST_REQUIRE_LE(l, r) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_REQUIRE_LE, l, r, le) - -#define DOCTEST_FAST_WARN_UNARY(v) DOCTEST_FAST_UNARY_ASSERT(DT_FAST_WARN_UNARY, v) -#define DOCTEST_FAST_CHECK_UNARY(v) DOCTEST_FAST_UNARY_ASSERT(DT_FAST_CHECK_UNARY, v) -#define DOCTEST_FAST_REQUIRE_UNARY(v) DOCTEST_FAST_UNARY_ASSERT(DT_FAST_REQUIRE_UNARY, v) -#define DOCTEST_FAST_WARN_UNARY_FALSE(v) DOCTEST_FAST_UNARY_ASSERT(DT_FAST_WARN_UNARY_FALSE, v) -#define DOCTEST_FAST_CHECK_UNARY_FALSE(v) DOCTEST_FAST_UNARY_ASSERT(DT_FAST_CHECK_UNARY_FALSE, v) -#define DOCTEST_FAST_REQUIRE_UNARY_FALSE(v) DOCTEST_FAST_UNARY_ASSERT(DT_FAST_REQUIRE_UNARY_FALSE, v) -#endif // DOCTEST_CONFIG_WITH_VARIADIC_MACROS +#define DOCTEST_WARN_MESSAGE(cond, ...) DOCTEST_FUNC_SCOPE_BEGIN { DOCTEST_INFO(__VA_ARGS__); DOCTEST_ASSERT_IMPLEMENT_2(DT_WARN, cond); } DOCTEST_FUNC_SCOPE_END +#define DOCTEST_CHECK_MESSAGE(cond, ...) DOCTEST_FUNC_SCOPE_BEGIN { DOCTEST_INFO(__VA_ARGS__); DOCTEST_ASSERT_IMPLEMENT_2(DT_CHECK, cond); } DOCTEST_FUNC_SCOPE_END +#define DOCTEST_REQUIRE_MESSAGE(cond, ...) DOCTEST_FUNC_SCOPE_BEGIN { DOCTEST_INFO(__VA_ARGS__); DOCTEST_ASSERT_IMPLEMENT_2(DT_REQUIRE, cond); } DOCTEST_FUNC_SCOPE_END +#define DOCTEST_WARN_FALSE_MESSAGE(cond, ...) DOCTEST_FUNC_SCOPE_BEGIN { DOCTEST_INFO(__VA_ARGS__); DOCTEST_ASSERT_IMPLEMENT_2(DT_WARN_FALSE, cond); } DOCTEST_FUNC_SCOPE_END +#define DOCTEST_CHECK_FALSE_MESSAGE(cond, ...) DOCTEST_FUNC_SCOPE_BEGIN { DOCTEST_INFO(__VA_ARGS__); DOCTEST_ASSERT_IMPLEMENT_2(DT_CHECK_FALSE, cond); } DOCTEST_FUNC_SCOPE_END +#define DOCTEST_REQUIRE_FALSE_MESSAGE(cond, ...) DOCTEST_FUNC_SCOPE_BEGIN { DOCTEST_INFO(__VA_ARGS__); DOCTEST_ASSERT_IMPLEMENT_2(DT_REQUIRE_FALSE, cond); } DOCTEST_FUNC_SCOPE_END // clang-format on -#ifdef DOCTEST_CONFIG_NO_EXCEPTIONS - -#undef DOCTEST_WARN_THROWS -#undef DOCTEST_CHECK_THROWS -#undef DOCTEST_REQUIRE_THROWS -#undef DOCTEST_WARN_THROWS_AS -#undef DOCTEST_CHECK_THROWS_AS -#undef DOCTEST_REQUIRE_THROWS_AS -#undef DOCTEST_WARN_NOTHROW -#undef DOCTEST_CHECK_NOTHROW -#undef DOCTEST_REQUIRE_NOTHROW - -#undef DOCTEST_WARN_THROWS_MESSAGE -#undef DOCTEST_CHECK_THROWS_MESSAGE -#undef DOCTEST_REQUIRE_THROWS_MESSAGE -#undef DOCTEST_WARN_THROWS_AS_MESSAGE -#undef DOCTEST_CHECK_THROWS_AS_MESSAGE -#undef DOCTEST_REQUIRE_THROWS_AS_MESSAGE -#undef DOCTEST_WARN_NOTHROW_MESSAGE -#undef DOCTEST_CHECK_NOTHROW_MESSAGE -#undef DOCTEST_REQUIRE_NOTHROW_MESSAGE - -#ifdef DOCTEST_CONFIG_NO_EXCEPTIONS_BUT_WITH_ALL_ASSERTS +#define DOCTEST_WARN_EQ(...) DOCTEST_BINARY_ASSERT(DT_WARN_EQ, eq, __VA_ARGS__) +#define DOCTEST_CHECK_EQ(...) DOCTEST_BINARY_ASSERT(DT_CHECK_EQ, eq, __VA_ARGS__) +#define DOCTEST_REQUIRE_EQ(...) DOCTEST_BINARY_ASSERT(DT_REQUIRE_EQ, eq, __VA_ARGS__) +#define DOCTEST_WARN_NE(...) DOCTEST_BINARY_ASSERT(DT_WARN_NE, ne, __VA_ARGS__) +#define DOCTEST_CHECK_NE(...) DOCTEST_BINARY_ASSERT(DT_CHECK_NE, ne, __VA_ARGS__) +#define DOCTEST_REQUIRE_NE(...) DOCTEST_BINARY_ASSERT(DT_REQUIRE_NE, ne, __VA_ARGS__) +#define DOCTEST_WARN_GT(...) DOCTEST_BINARY_ASSERT(DT_WARN_GT, gt, __VA_ARGS__) +#define DOCTEST_CHECK_GT(...) DOCTEST_BINARY_ASSERT(DT_CHECK_GT, gt, __VA_ARGS__) +#define DOCTEST_REQUIRE_GT(...) DOCTEST_BINARY_ASSERT(DT_REQUIRE_GT, gt, __VA_ARGS__) +#define DOCTEST_WARN_LT(...) DOCTEST_BINARY_ASSERT(DT_WARN_LT, lt, __VA_ARGS__) +#define DOCTEST_CHECK_LT(...) DOCTEST_BINARY_ASSERT(DT_CHECK_LT, lt, __VA_ARGS__) +#define DOCTEST_REQUIRE_LT(...) DOCTEST_BINARY_ASSERT(DT_REQUIRE_LT, lt, __VA_ARGS__) +#define DOCTEST_WARN_GE(...) DOCTEST_BINARY_ASSERT(DT_WARN_GE, ge, __VA_ARGS__) +#define DOCTEST_CHECK_GE(...) DOCTEST_BINARY_ASSERT(DT_CHECK_GE, ge, __VA_ARGS__) +#define DOCTEST_REQUIRE_GE(...) DOCTEST_BINARY_ASSERT(DT_REQUIRE_GE, ge, __VA_ARGS__) +#define DOCTEST_WARN_LE(...) DOCTEST_BINARY_ASSERT(DT_WARN_LE, le, __VA_ARGS__) +#define DOCTEST_CHECK_LE(...) DOCTEST_BINARY_ASSERT(DT_CHECK_LE, le, __VA_ARGS__) +#define DOCTEST_REQUIRE_LE(...) DOCTEST_BINARY_ASSERT(DT_REQUIRE_LE, le, __VA_ARGS__) + +#define DOCTEST_WARN_UNARY(...) DOCTEST_UNARY_ASSERT(DT_WARN_UNARY, __VA_ARGS__) +#define DOCTEST_CHECK_UNARY(...) DOCTEST_UNARY_ASSERT(DT_CHECK_UNARY, __VA_ARGS__) +#define DOCTEST_REQUIRE_UNARY(...) DOCTEST_UNARY_ASSERT(DT_REQUIRE_UNARY, __VA_ARGS__) +#define DOCTEST_WARN_UNARY_FALSE(...) DOCTEST_UNARY_ASSERT(DT_WARN_UNARY_FALSE, __VA_ARGS__) +#define DOCTEST_CHECK_UNARY_FALSE(...) DOCTEST_UNARY_ASSERT(DT_CHECK_UNARY_FALSE, __VA_ARGS__) +#define DOCTEST_REQUIRE_UNARY_FALSE(...) DOCTEST_UNARY_ASSERT(DT_REQUIRE_UNARY_FALSE, __VA_ARGS__) -#define DOCTEST_WARN_THROWS(expr) ((void)0) -#define DOCTEST_CHECK_THROWS(expr) ((void)0) -#define DOCTEST_REQUIRE_THROWS(expr) ((void)0) -#ifdef DOCTEST_CONFIG_WITH_VARIADIC_MACROS -#define DOCTEST_WARN_THROWS_AS(expr, ...) ((void)0) -#define DOCTEST_CHECK_THROWS_AS(expr, ...) ((void)0) -#define DOCTEST_REQUIRE_THROWS_AS(expr, ...) ((void)0) -#else // DOCTEST_CONFIG_WITH_VARIADIC_MACROS -#define DOCTEST_WARN_THROWS_AS(expr, ex) ((void)0) -#define DOCTEST_CHECK_THROWS_AS(expr, ex) ((void)0) -#define DOCTEST_REQUIRE_THROWS_AS(expr, ex) ((void)0) -#endif // DOCTEST_CONFIG_WITH_VARIADIC_MACROS -#define DOCTEST_WARN_NOTHROW(expr) ((void)0) -#define DOCTEST_CHECK_NOTHROW(expr) ((void)0) -#define DOCTEST_REQUIRE_NOTHROW(expr) ((void)0) - -#define DOCTEST_WARN_THROWS_MESSAGE(expr, msg) ((void)0) -#define DOCTEST_CHECK_THROWS_MESSAGE(expr, msg) ((void)0) -#define DOCTEST_REQUIRE_THROWS_MESSAGE(expr, msg) ((void)0) -#define DOCTEST_WARN_THROWS_AS_MESSAGE(expr, ex, msg) ((void)0) -#define DOCTEST_CHECK_THROWS_AS_MESSAGE(expr, ex, msg) ((void)0) -#define DOCTEST_REQUIRE_THROWS_AS_MESSAGE(expr, ex, msg) ((void)0) -#define DOCTEST_WARN_NOTHROW_MESSAGE(expr, msg) ((void)0) -#define DOCTEST_CHECK_NOTHROW_MESSAGE(expr, msg) ((void)0) -#define DOCTEST_REQUIRE_NOTHROW_MESSAGE(expr, msg) ((void)0) +#ifndef DOCTEST_CONFIG_NO_EXCEPTIONS -#else // DOCTEST_CONFIG_NO_EXCEPTIONS_BUT_WITH_ALL_ASSERTS +#define DOCTEST_ASSERT_THROWS_AS(expr, assert_type, message, ...) \ + DOCTEST_FUNC_SCOPE_BEGIN { \ + if(!doctest::getContextOptions()->no_throw) { \ + doctest::detail::ResultBuilder DOCTEST_RB(doctest::assertType::assert_type, __FILE__, \ + __LINE__, #expr, #__VA_ARGS__, message); \ + try { \ + DOCTEST_CAST_TO_VOID(expr) \ + } catch(const typename doctest::detail::types::remove_const< \ + typename doctest::detail::types::remove_reference<__VA_ARGS__>::type>::type&) {\ + DOCTEST_RB.translateException(); \ + DOCTEST_RB.m_threw_as = true; \ + } catch(...) { DOCTEST_RB.translateException(); } \ + DOCTEST_ASSERT_LOG_REACT_RETURN(DOCTEST_RB); \ + } else { /* NOLINT(*-else-after-return) */ \ + DOCTEST_FUNC_SCOPE_RET(false); \ + } \ + } DOCTEST_FUNC_SCOPE_END -#undef DOCTEST_REQUIRE -#undef DOCTEST_REQUIRE_FALSE -#undef DOCTEST_REQUIRE_MESSAGE -#undef DOCTEST_REQUIRE_FALSE_MESSAGE -#undef DOCTEST_REQUIRE_EQ -#undef DOCTEST_REQUIRE_NE -#undef DOCTEST_REQUIRE_GT -#undef DOCTEST_REQUIRE_LT -#undef DOCTEST_REQUIRE_GE -#undef DOCTEST_REQUIRE_LE -#undef DOCTEST_REQUIRE_UNARY -#undef DOCTEST_REQUIRE_UNARY_FALSE -#undef DOCTEST_FAST_REQUIRE_EQ -#undef DOCTEST_FAST_REQUIRE_NE -#undef DOCTEST_FAST_REQUIRE_GT -#undef DOCTEST_FAST_REQUIRE_LT -#undef DOCTEST_FAST_REQUIRE_GE -#undef DOCTEST_FAST_REQUIRE_LE -#undef DOCTEST_FAST_REQUIRE_UNARY -#undef DOCTEST_FAST_REQUIRE_UNARY_FALSE +#define DOCTEST_ASSERT_THROWS_WITH(expr, expr_str, assert_type, ...) \ + DOCTEST_FUNC_SCOPE_BEGIN { \ + if(!doctest::getContextOptions()->no_throw) { \ + doctest::detail::ResultBuilder DOCTEST_RB(doctest::assertType::assert_type, __FILE__, \ + __LINE__, expr_str, "", __VA_ARGS__); \ + try { \ + DOCTEST_CAST_TO_VOID(expr) \ + } catch(...) { DOCTEST_RB.translateException(); } \ + DOCTEST_ASSERT_LOG_REACT_RETURN(DOCTEST_RB); \ + } else { /* NOLINT(*-else-after-return) */ \ + DOCTEST_FUNC_SCOPE_RET(false); \ + } \ + } DOCTEST_FUNC_SCOPE_END + +#define DOCTEST_ASSERT_NOTHROW(assert_type, ...) \ + DOCTEST_FUNC_SCOPE_BEGIN { \ + doctest::detail::ResultBuilder DOCTEST_RB(doctest::assertType::assert_type, __FILE__, \ + __LINE__, #__VA_ARGS__); \ + try { \ + DOCTEST_CAST_TO_VOID(__VA_ARGS__) \ + } catch(...) { DOCTEST_RB.translateException(); } \ + DOCTEST_ASSERT_LOG_REACT_RETURN(DOCTEST_RB); \ + } DOCTEST_FUNC_SCOPE_END -#endif // DOCTEST_CONFIG_NO_EXCEPTIONS_BUT_WITH_ALL_ASSERTS +// clang-format off +#define DOCTEST_WARN_THROWS(...) DOCTEST_ASSERT_THROWS_WITH((__VA_ARGS__), #__VA_ARGS__, DT_WARN_THROWS, "") +#define DOCTEST_CHECK_THROWS(...) DOCTEST_ASSERT_THROWS_WITH((__VA_ARGS__), #__VA_ARGS__, DT_CHECK_THROWS, "") +#define DOCTEST_REQUIRE_THROWS(...) DOCTEST_ASSERT_THROWS_WITH((__VA_ARGS__), #__VA_ARGS__, DT_REQUIRE_THROWS, "") + +#define DOCTEST_WARN_THROWS_AS(expr, ...) DOCTEST_ASSERT_THROWS_AS(expr, DT_WARN_THROWS_AS, "", __VA_ARGS__) +#define DOCTEST_CHECK_THROWS_AS(expr, ...) DOCTEST_ASSERT_THROWS_AS(expr, DT_CHECK_THROWS_AS, "", __VA_ARGS__) +#define DOCTEST_REQUIRE_THROWS_AS(expr, ...) DOCTEST_ASSERT_THROWS_AS(expr, DT_REQUIRE_THROWS_AS, "", __VA_ARGS__) + +#define DOCTEST_WARN_THROWS_WITH(expr, ...) DOCTEST_ASSERT_THROWS_WITH(expr, #expr, DT_WARN_THROWS_WITH, __VA_ARGS__) +#define DOCTEST_CHECK_THROWS_WITH(expr, ...) DOCTEST_ASSERT_THROWS_WITH(expr, #expr, DT_CHECK_THROWS_WITH, __VA_ARGS__) +#define DOCTEST_REQUIRE_THROWS_WITH(expr, ...) DOCTEST_ASSERT_THROWS_WITH(expr, #expr, DT_REQUIRE_THROWS_WITH, __VA_ARGS__) + +#define DOCTEST_WARN_THROWS_WITH_AS(expr, message, ...) DOCTEST_ASSERT_THROWS_AS(expr, DT_WARN_THROWS_WITH_AS, message, __VA_ARGS__) +#define DOCTEST_CHECK_THROWS_WITH_AS(expr, message, ...) DOCTEST_ASSERT_THROWS_AS(expr, DT_CHECK_THROWS_WITH_AS, message, __VA_ARGS__) +#define DOCTEST_REQUIRE_THROWS_WITH_AS(expr, message, ...) DOCTEST_ASSERT_THROWS_AS(expr, DT_REQUIRE_THROWS_WITH_AS, message, __VA_ARGS__) + +#define DOCTEST_WARN_NOTHROW(...) DOCTEST_ASSERT_NOTHROW(DT_WARN_NOTHROW, __VA_ARGS__) +#define DOCTEST_CHECK_NOTHROW(...) DOCTEST_ASSERT_NOTHROW(DT_CHECK_NOTHROW, __VA_ARGS__) +#define DOCTEST_REQUIRE_NOTHROW(...) DOCTEST_ASSERT_NOTHROW(DT_REQUIRE_NOTHROW, __VA_ARGS__) + +#define DOCTEST_WARN_THROWS_MESSAGE(expr, ...) DOCTEST_FUNC_SCOPE_BEGIN { DOCTEST_INFO(__VA_ARGS__); DOCTEST_WARN_THROWS(expr); } DOCTEST_FUNC_SCOPE_END +#define DOCTEST_CHECK_THROWS_MESSAGE(expr, ...) DOCTEST_FUNC_SCOPE_BEGIN { DOCTEST_INFO(__VA_ARGS__); DOCTEST_CHECK_THROWS(expr); } DOCTEST_FUNC_SCOPE_END +#define DOCTEST_REQUIRE_THROWS_MESSAGE(expr, ...) DOCTEST_FUNC_SCOPE_BEGIN { DOCTEST_INFO(__VA_ARGS__); DOCTEST_REQUIRE_THROWS(expr); } DOCTEST_FUNC_SCOPE_END +#define DOCTEST_WARN_THROWS_AS_MESSAGE(expr, ex, ...) DOCTEST_FUNC_SCOPE_BEGIN { DOCTEST_INFO(__VA_ARGS__); DOCTEST_WARN_THROWS_AS(expr, ex); } DOCTEST_FUNC_SCOPE_END +#define DOCTEST_CHECK_THROWS_AS_MESSAGE(expr, ex, ...) DOCTEST_FUNC_SCOPE_BEGIN { DOCTEST_INFO(__VA_ARGS__); DOCTEST_CHECK_THROWS_AS(expr, ex); } DOCTEST_FUNC_SCOPE_END +#define DOCTEST_REQUIRE_THROWS_AS_MESSAGE(expr, ex, ...) DOCTEST_FUNC_SCOPE_BEGIN { DOCTEST_INFO(__VA_ARGS__); DOCTEST_REQUIRE_THROWS_AS(expr, ex); } DOCTEST_FUNC_SCOPE_END +#define DOCTEST_WARN_THROWS_WITH_MESSAGE(expr, with, ...) DOCTEST_FUNC_SCOPE_BEGIN { DOCTEST_INFO(__VA_ARGS__); DOCTEST_WARN_THROWS_WITH(expr, with); } DOCTEST_FUNC_SCOPE_END +#define DOCTEST_CHECK_THROWS_WITH_MESSAGE(expr, with, ...) DOCTEST_FUNC_SCOPE_BEGIN { DOCTEST_INFO(__VA_ARGS__); DOCTEST_CHECK_THROWS_WITH(expr, with); } DOCTEST_FUNC_SCOPE_END +#define DOCTEST_REQUIRE_THROWS_WITH_MESSAGE(expr, with, ...) DOCTEST_FUNC_SCOPE_BEGIN { DOCTEST_INFO(__VA_ARGS__); DOCTEST_REQUIRE_THROWS_WITH(expr, with); } DOCTEST_FUNC_SCOPE_END +#define DOCTEST_WARN_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) DOCTEST_FUNC_SCOPE_BEGIN { DOCTEST_INFO(__VA_ARGS__); DOCTEST_WARN_THROWS_WITH_AS(expr, with, ex); } DOCTEST_FUNC_SCOPE_END +#define DOCTEST_CHECK_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) DOCTEST_FUNC_SCOPE_BEGIN { DOCTEST_INFO(__VA_ARGS__); DOCTEST_CHECK_THROWS_WITH_AS(expr, with, ex); } DOCTEST_FUNC_SCOPE_END +#define DOCTEST_REQUIRE_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) DOCTEST_FUNC_SCOPE_BEGIN { DOCTEST_INFO(__VA_ARGS__); DOCTEST_REQUIRE_THROWS_WITH_AS(expr, with, ex); } DOCTEST_FUNC_SCOPE_END +#define DOCTEST_WARN_NOTHROW_MESSAGE(expr, ...) DOCTEST_FUNC_SCOPE_BEGIN { DOCTEST_INFO(__VA_ARGS__); DOCTEST_WARN_NOTHROW(expr); } DOCTEST_FUNC_SCOPE_END +#define DOCTEST_CHECK_NOTHROW_MESSAGE(expr, ...) DOCTEST_FUNC_SCOPE_BEGIN { DOCTEST_INFO(__VA_ARGS__); DOCTEST_CHECK_NOTHROW(expr); } DOCTEST_FUNC_SCOPE_END +#define DOCTEST_REQUIRE_NOTHROW_MESSAGE(expr, ...) DOCTEST_FUNC_SCOPE_BEGIN { DOCTEST_INFO(__VA_ARGS__); DOCTEST_REQUIRE_NOTHROW(expr); } DOCTEST_FUNC_SCOPE_END +// clang-format on #endif // DOCTEST_CONFIG_NO_EXCEPTIONS @@ -2759,10 +2527,9 @@ constexpr T to_lvalue = x; #else // DOCTEST_CONFIG_DISABLE #define DOCTEST_IMPLEMENT_FIXTURE(der, base, func, name) \ - namespace \ - { \ + namespace /* NOLINT */ { \ template \ - struct der : base \ + struct der : public base \ { void f(); }; \ } \ template \ @@ -2774,387 +2541,505 @@ constexpr T to_lvalue = x; // for registering tests #define DOCTEST_TEST_CASE(name) \ - DOCTEST_CREATE_AND_REGISTER_FUNCTION(DOCTEST_ANONYMOUS(_DOCTEST_ANON_FUNC_), name) + DOCTEST_CREATE_AND_REGISTER_FUNCTION(DOCTEST_ANONYMOUS(DOCTEST_ANON_FUNC_), name) + +// for registering tests in classes +#define DOCTEST_TEST_CASE_CLASS(name) \ + DOCTEST_CREATE_AND_REGISTER_FUNCTION(DOCTEST_ANONYMOUS(DOCTEST_ANON_FUNC_), name) // for registering tests with a fixture #define DOCTEST_TEST_CASE_FIXTURE(x, name) \ - DOCTEST_IMPLEMENT_FIXTURE(DOCTEST_ANONYMOUS(_DOCTEST_ANON_CLASS_), x, \ - DOCTEST_ANONYMOUS(_DOCTEST_ANON_FUNC_), name) + DOCTEST_IMPLEMENT_FIXTURE(DOCTEST_ANONYMOUS(DOCTEST_ANON_CLASS_), x, \ + DOCTEST_ANONYMOUS(DOCTEST_ANON_FUNC_), name) // for converting types to strings without the header and demangling -#ifdef DOCTEST_CONFIG_WITH_VARIADIC_MACROS -#define DOCTEST_TYPE_TO_STRING(...) typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_) -#define DOCTEST_TYPE_TO_STRING_IMPL(...) -#else // DOCTEST_CONFIG_WITH_VARIADIC_MACROS -#define DOCTEST_TYPE_TO_STRING(x) typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_) -#define DOCTEST_TYPE_TO_STRING_IMPL(x) -#endif // DOCTEST_CONFIG_WITH_VARIADIC_MACROS +#define DOCTEST_TYPE_TO_STRING_AS(str, ...) static_assert(true, "") +#define DOCTEST_TYPE_TO_STRING(...) static_assert(true, "") // for typed tests -#define DOCTEST_TEST_CASE_TEMPLATE(name, type, types) \ +#define DOCTEST_TEST_CASE_TEMPLATE(name, type, ...) \ template \ - inline void DOCTEST_ANONYMOUS(_DOCTEST_ANON_TMP_)() + inline void DOCTEST_ANONYMOUS(DOCTEST_ANON_TMP_)() #define DOCTEST_TEST_CASE_TEMPLATE_DEFINE(name, type, id) \ template \ - inline void DOCTEST_ANONYMOUS(_DOCTEST_ANON_TMP_)() + inline void DOCTEST_ANONYMOUS(DOCTEST_ANON_TMP_)() -#define DOCTEST_TEST_CASE_TEMPLATE_INSTANTIATE(id, types) \ - typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_) +#define DOCTEST_TEST_CASE_TEMPLATE_INVOKE(id, ...) static_assert(true, "") +#define DOCTEST_TEST_CASE_TEMPLATE_APPLY(id, ...) static_assert(true, "") // for subcases #define DOCTEST_SUBCASE(name) // for a testsuite block -#define DOCTEST_TEST_SUITE(name) namespace +#define DOCTEST_TEST_SUITE(name) namespace // NOLINT // for starting a testsuite block -#define DOCTEST_TEST_SUITE_BEGIN(name) typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_) +#define DOCTEST_TEST_SUITE_BEGIN(name) static_assert(true, "") // for ending a testsuite block -#define DOCTEST_TEST_SUITE_END typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_) +#define DOCTEST_TEST_SUITE_END using DOCTEST_ANONYMOUS(DOCTEST_ANON_FOR_SEMICOLON_) = int #define DOCTEST_REGISTER_EXCEPTION_TRANSLATOR(signature) \ template \ - static inline doctest::String DOCTEST_ANONYMOUS(_DOCTEST_ANON_TRANSLATOR_)(signature) - -#define DOCTEST_INFO(x) ((void)0) -#define DOCTEST_CAPTURE(x) ((void)0) -#define DOCTEST_ADD_MESSAGE_AT(file, line, x) ((void)0) -#define DOCTEST_ADD_FAIL_CHECK_AT(file, line, x) ((void)0) -#define DOCTEST_ADD_FAIL_AT(file, line, x) ((void)0) -#define DOCTEST_MESSAGE(x) ((void)0) -#define DOCTEST_FAIL_CHECK(x) ((void)0) -#define DOCTEST_FAIL(x) ((void)0) - -#ifdef DOCTEST_CONFIG_WITH_VARIADIC_MACROS -#define DOCTEST_WARN(...) ((void)0) -#define DOCTEST_CHECK(...) ((void)0) -#define DOCTEST_REQUIRE(...) ((void)0) -#define DOCTEST_WARN_FALSE(...) ((void)0) -#define DOCTEST_CHECK_FALSE(...) ((void)0) -#define DOCTEST_REQUIRE_FALSE(...) ((void)0) -#else // DOCTEST_CONFIG_WITH_VARIADIC_MACROS -#define DOCTEST_WARN(expr) ((void)0) -#define DOCTEST_CHECK(expr) ((void)0) -#define DOCTEST_REQUIRE(expr) ((void)0) -#define DOCTEST_WARN_FALSE(expr) ((void)0) -#define DOCTEST_CHECK_FALSE(expr) ((void)0) -#define DOCTEST_REQUIRE_FALSE(expr) ((void)0) -#endif // DOCTEST_CONFIG_WITH_VARIADIC_MACROS - -#define DOCTEST_WARN_MESSAGE(cond, msg) ((void)0) -#define DOCTEST_CHECK_MESSAGE(cond, msg) ((void)0) -#define DOCTEST_REQUIRE_MESSAGE(cond, msg) ((void)0) -#define DOCTEST_WARN_FALSE_MESSAGE(cond, msg) ((void)0) -#define DOCTEST_CHECK_FALSE_MESSAGE(cond, msg) ((void)0) -#define DOCTEST_REQUIRE_FALSE_MESSAGE(cond, msg) ((void)0) - -#define DOCTEST_WARN_THROWS(expr) ((void)0) -#define DOCTEST_CHECK_THROWS(expr) ((void)0) -#define DOCTEST_REQUIRE_THROWS(expr) ((void)0) -#ifdef DOCTEST_CONFIG_WITH_VARIADIC_MACROS -#define DOCTEST_WARN_THROWS_AS(expr, ...) ((void)0) -#define DOCTEST_CHECK_THROWS_AS(expr, ...) ((void)0) -#define DOCTEST_REQUIRE_THROWS_AS(expr, ...) ((void)0) -#else // DOCTEST_CONFIG_WITH_VARIADIC_MACROS -#define DOCTEST_WARN_THROWS_AS(expr, ex) ((void)0) -#define DOCTEST_CHECK_THROWS_AS(expr, ex) ((void)0) -#define DOCTEST_REQUIRE_THROWS_AS(expr, ex) ((void)0) -#endif // DOCTEST_CONFIG_WITH_VARIADIC_MACROS -#define DOCTEST_WARN_NOTHROW(expr) ((void)0) -#define DOCTEST_CHECK_NOTHROW(expr) ((void)0) -#define DOCTEST_REQUIRE_NOTHROW(expr) ((void)0) - -#define DOCTEST_WARN_THROWS_MESSAGE(expr, msg) ((void)0) -#define DOCTEST_CHECK_THROWS_MESSAGE(expr, msg) ((void)0) -#define DOCTEST_REQUIRE_THROWS_MESSAGE(expr, msg) ((void)0) -#define DOCTEST_WARN_THROWS_AS_MESSAGE(expr, ex, msg) ((void)0) -#define DOCTEST_CHECK_THROWS_AS_MESSAGE(expr, ex, msg) ((void)0) -#define DOCTEST_REQUIRE_THROWS_AS_MESSAGE(expr, ex, msg) ((void)0) -#define DOCTEST_WARN_NOTHROW_MESSAGE(expr, msg) ((void)0) -#define DOCTEST_CHECK_NOTHROW_MESSAGE(expr, msg) ((void)0) -#define DOCTEST_REQUIRE_NOTHROW_MESSAGE(expr, msg) ((void)0) - -#ifdef DOCTEST_CONFIG_WITH_VARIADIC_MACROS - -#define DOCTEST_WARN_EQ(...) ((void)0) -#define DOCTEST_CHECK_EQ(...) ((void)0) -#define DOCTEST_REQUIRE_EQ(...) ((void)0) -#define DOCTEST_WARN_NE(...) ((void)0) -#define DOCTEST_CHECK_NE(...) ((void)0) -#define DOCTEST_REQUIRE_NE(...) ((void)0) -#define DOCTEST_WARN_GT(...) ((void)0) -#define DOCTEST_CHECK_GT(...) ((void)0) -#define DOCTEST_REQUIRE_GT(...) ((void)0) -#define DOCTEST_WARN_LT(...) ((void)0) -#define DOCTEST_CHECK_LT(...) ((void)0) -#define DOCTEST_REQUIRE_LT(...) ((void)0) -#define DOCTEST_WARN_GE(...) ((void)0) -#define DOCTEST_CHECK_GE(...) ((void)0) -#define DOCTEST_REQUIRE_GE(...) ((void)0) -#define DOCTEST_WARN_LE(...) ((void)0) -#define DOCTEST_CHECK_LE(...) ((void)0) -#define DOCTEST_REQUIRE_LE(...) ((void)0) - -#define DOCTEST_WARN_UNARY(...) ((void)0) -#define DOCTEST_CHECK_UNARY(...) ((void)0) -#define DOCTEST_REQUIRE_UNARY(...) ((void)0) -#define DOCTEST_WARN_UNARY_FALSE(...) ((void)0) -#define DOCTEST_CHECK_UNARY_FALSE(...) ((void)0) -#define DOCTEST_REQUIRE_UNARY_FALSE(...) ((void)0) - -#define DOCTEST_FAST_WARN_EQ(...) ((void)0) -#define DOCTEST_FAST_CHECK_EQ(...) ((void)0) -#define DOCTEST_FAST_REQUIRE_EQ(...) ((void)0) -#define DOCTEST_FAST_WARN_NE(...) ((void)0) -#define DOCTEST_FAST_CHECK_NE(...) ((void)0) -#define DOCTEST_FAST_REQUIRE_NE(...) ((void)0) -#define DOCTEST_FAST_WARN_GT(...) ((void)0) -#define DOCTEST_FAST_CHECK_GT(...) ((void)0) -#define DOCTEST_FAST_REQUIRE_GT(...) ((void)0) -#define DOCTEST_FAST_WARN_LT(...) ((void)0) -#define DOCTEST_FAST_CHECK_LT(...) ((void)0) -#define DOCTEST_FAST_REQUIRE_LT(...) ((void)0) -#define DOCTEST_FAST_WARN_GE(...) ((void)0) -#define DOCTEST_FAST_CHECK_GE(...) ((void)0) -#define DOCTEST_FAST_REQUIRE_GE(...) ((void)0) -#define DOCTEST_FAST_WARN_LE(...) ((void)0) -#define DOCTEST_FAST_CHECK_LE(...) ((void)0) -#define DOCTEST_FAST_REQUIRE_LE(...) ((void)0) - -#define DOCTEST_FAST_WARN_UNARY(...) ((void)0) -#define DOCTEST_FAST_CHECK_UNARY(...) ((void)0) -#define DOCTEST_FAST_REQUIRE_UNARY(...) ((void)0) -#define DOCTEST_FAST_WARN_UNARY_FALSE(...) ((void)0) -#define DOCTEST_FAST_CHECK_UNARY_FALSE(...) ((void)0) -#define DOCTEST_FAST_REQUIRE_UNARY_FALSE(...) ((void)0) - -#else // DOCTEST_CONFIG_WITH_VARIADIC_MACROS - -#define DOCTEST_WARN_EQ(lhs, rhs) ((void)0) -#define DOCTEST_CHECK_EQ(lhs, rhs) ((void)0) -#define DOCTEST_REQUIRE_EQ(lhs, rhs) ((void)0) -#define DOCTEST_WARN_NE(lhs, rhs) ((void)0) -#define DOCTEST_CHECK_NE(lhs, rhs) ((void)0) -#define DOCTEST_REQUIRE_NE(lhs, rhs) ((void)0) -#define DOCTEST_WARN_GT(lhs, rhs) ((void)0) -#define DOCTEST_CHECK_GT(lhs, rhs) ((void)0) -#define DOCTEST_REQUIRE_GT(lhs, rhs) ((void)0) -#define DOCTEST_WARN_LT(lhs, rhs) ((void)0) -#define DOCTEST_CHECK_LT(lhs, rhs) ((void)0) -#define DOCTEST_REQUIRE_LT(lhs, rhs) ((void)0) -#define DOCTEST_WARN_GE(lhs, rhs) ((void)0) -#define DOCTEST_CHECK_GE(lhs, rhs) ((void)0) -#define DOCTEST_REQUIRE_GE(lhs, rhs) ((void)0) -#define DOCTEST_WARN_LE(lhs, rhs) ((void)0) -#define DOCTEST_CHECK_LE(lhs, rhs) ((void)0) -#define DOCTEST_REQUIRE_LE(lhs, rhs) ((void)0) - -#define DOCTEST_WARN_UNARY(val) ((void)0) -#define DOCTEST_CHECK_UNARY(val) ((void)0) -#define DOCTEST_REQUIRE_UNARY(val) ((void)0) -#define DOCTEST_WARN_UNARY_FALSE(val) ((void)0) -#define DOCTEST_CHECK_UNARY_FALSE(val) ((void)0) -#define DOCTEST_REQUIRE_UNARY_FALSE(val) ((void)0) - -#define DOCTEST_FAST_WARN_EQ(lhs, rhs) ((void)0) -#define DOCTEST_FAST_CHECK_EQ(lhs, rhs) ((void)0) -#define DOCTEST_FAST_REQUIRE_EQ(lhs, rhs) ((void)0) -#define DOCTEST_FAST_WARN_NE(lhs, rhs) ((void)0) -#define DOCTEST_FAST_CHECK_NE(lhs, rhs) ((void)0) -#define DOCTEST_FAST_REQUIRE_NE(lhs, rhs) ((void)0) -#define DOCTEST_FAST_WARN_GT(lhs, rhs) ((void)0) -#define DOCTEST_FAST_CHECK_GT(lhs, rhs) ((void)0) -#define DOCTEST_FAST_REQUIRE_GT(lhs, rhs) ((void)0) -#define DOCTEST_FAST_WARN_LT(lhs, rhs) ((void)0) -#define DOCTEST_FAST_CHECK_LT(lhs, rhs) ((void)0) -#define DOCTEST_FAST_REQUIRE_LT(lhs, rhs) ((void)0) -#define DOCTEST_FAST_WARN_GE(lhs, rhs) ((void)0) -#define DOCTEST_FAST_CHECK_GE(lhs, rhs) ((void)0) -#define DOCTEST_FAST_REQUIRE_GE(lhs, rhs) ((void)0) -#define DOCTEST_FAST_WARN_LE(lhs, rhs) ((void)0) -#define DOCTEST_FAST_CHECK_LE(lhs, rhs) ((void)0) -#define DOCTEST_FAST_REQUIRE_LE(lhs, rhs) ((void)0) - -#define DOCTEST_FAST_WARN_UNARY(val) ((void)0) -#define DOCTEST_FAST_CHECK_UNARY(val) ((void)0) -#define DOCTEST_FAST_REQUIRE_UNARY(val) ((void)0) -#define DOCTEST_FAST_WARN_UNARY_FALSE(val) ((void)0) -#define DOCTEST_FAST_CHECK_UNARY_FALSE(val) ((void)0) -#define DOCTEST_FAST_REQUIRE_UNARY_FALSE(val) ((void)0) - -#endif // DOCTEST_CONFIG_WITH_VARIADIC_MACROS + static inline doctest::String DOCTEST_ANONYMOUS(DOCTEST_ANON_TRANSLATOR_)(signature) + +#define DOCTEST_REGISTER_REPORTER(name, priority, reporter) +#define DOCTEST_REGISTER_LISTENER(name, priority, reporter) + +#define DOCTEST_INFO(...) (static_cast(0)) +#define DOCTEST_CAPTURE(x) (static_cast(0)) +#define DOCTEST_ADD_MESSAGE_AT(file, line, ...) (static_cast(0)) +#define DOCTEST_ADD_FAIL_CHECK_AT(file, line, ...) (static_cast(0)) +#define DOCTEST_ADD_FAIL_AT(file, line, ...) (static_cast(0)) +#define DOCTEST_MESSAGE(...) (static_cast(0)) +#define DOCTEST_FAIL_CHECK(...) (static_cast(0)) +#define DOCTEST_FAIL(...) (static_cast(0)) + +#if defined(DOCTEST_CONFIG_EVALUATE_ASSERTS_EVEN_WHEN_DISABLED) \ + && defined(DOCTEST_CONFIG_ASSERTS_RETURN_VALUES) + +#define DOCTEST_WARN(...) [&] { return __VA_ARGS__; }() +#define DOCTEST_CHECK(...) [&] { return __VA_ARGS__; }() +#define DOCTEST_REQUIRE(...) [&] { return __VA_ARGS__; }() +#define DOCTEST_WARN_FALSE(...) [&] { return !(__VA_ARGS__); }() +#define DOCTEST_CHECK_FALSE(...) [&] { return !(__VA_ARGS__); }() +#define DOCTEST_REQUIRE_FALSE(...) [&] { return !(__VA_ARGS__); }() + +#define DOCTEST_WARN_MESSAGE(cond, ...) [&] { return cond; }() +#define DOCTEST_CHECK_MESSAGE(cond, ...) [&] { return cond; }() +#define DOCTEST_REQUIRE_MESSAGE(cond, ...) [&] { return cond; }() +#define DOCTEST_WARN_FALSE_MESSAGE(cond, ...) [&] { return !(cond); }() +#define DOCTEST_CHECK_FALSE_MESSAGE(cond, ...) [&] { return !(cond); }() +#define DOCTEST_REQUIRE_FALSE_MESSAGE(cond, ...) [&] { return !(cond); }() + +namespace doctest { +namespace detail { +#define DOCTEST_RELATIONAL_OP(name, op) \ + template \ + bool name(const DOCTEST_REF_WRAP(L) lhs, const DOCTEST_REF_WRAP(R) rhs) { return lhs op rhs; } + + DOCTEST_RELATIONAL_OP(eq, ==) + DOCTEST_RELATIONAL_OP(ne, !=) + DOCTEST_RELATIONAL_OP(lt, <) + DOCTEST_RELATIONAL_OP(gt, >) + DOCTEST_RELATIONAL_OP(le, <=) + DOCTEST_RELATIONAL_OP(ge, >=) +} // namespace detail +} // namespace doctest + +#define DOCTEST_WARN_EQ(...) [&] { return doctest::detail::eq(__VA_ARGS__); }() +#define DOCTEST_CHECK_EQ(...) [&] { return doctest::detail::eq(__VA_ARGS__); }() +#define DOCTEST_REQUIRE_EQ(...) [&] { return doctest::detail::eq(__VA_ARGS__); }() +#define DOCTEST_WARN_NE(...) [&] { return doctest::detail::ne(__VA_ARGS__); }() +#define DOCTEST_CHECK_NE(...) [&] { return doctest::detail::ne(__VA_ARGS__); }() +#define DOCTEST_REQUIRE_NE(...) [&] { return doctest::detail::ne(__VA_ARGS__); }() +#define DOCTEST_WARN_LT(...) [&] { return doctest::detail::lt(__VA_ARGS__); }() +#define DOCTEST_CHECK_LT(...) [&] { return doctest::detail::lt(__VA_ARGS__); }() +#define DOCTEST_REQUIRE_LT(...) [&] { return doctest::detail::lt(__VA_ARGS__); }() +#define DOCTEST_WARN_GT(...) [&] { return doctest::detail::gt(__VA_ARGS__); }() +#define DOCTEST_CHECK_GT(...) [&] { return doctest::detail::gt(__VA_ARGS__); }() +#define DOCTEST_REQUIRE_GT(...) [&] { return doctest::detail::gt(__VA_ARGS__); }() +#define DOCTEST_WARN_LE(...) [&] { return doctest::detail::le(__VA_ARGS__); }() +#define DOCTEST_CHECK_LE(...) [&] { return doctest::detail::le(__VA_ARGS__); }() +#define DOCTEST_REQUIRE_LE(...) [&] { return doctest::detail::le(__VA_ARGS__); }() +#define DOCTEST_WARN_GE(...) [&] { return doctest::detail::ge(__VA_ARGS__); }() +#define DOCTEST_CHECK_GE(...) [&] { return doctest::detail::ge(__VA_ARGS__); }() +#define DOCTEST_REQUIRE_GE(...) [&] { return doctest::detail::ge(__VA_ARGS__); }() +#define DOCTEST_WARN_UNARY(...) [&] { return __VA_ARGS__; }() +#define DOCTEST_CHECK_UNARY(...) [&] { return __VA_ARGS__; }() +#define DOCTEST_REQUIRE_UNARY(...) [&] { return __VA_ARGS__; }() +#define DOCTEST_WARN_UNARY_FALSE(...) [&] { return !(__VA_ARGS__); }() +#define DOCTEST_CHECK_UNARY_FALSE(...) [&] { return !(__VA_ARGS__); }() +#define DOCTEST_REQUIRE_UNARY_FALSE(...) [&] { return !(__VA_ARGS__); }() + +#ifndef DOCTEST_CONFIG_NO_EXCEPTIONS + +#define DOCTEST_WARN_THROWS_WITH(expr, with, ...) [] { static_assert(false, "Exception translation is not available when doctest is disabled."); return false; }() +#define DOCTEST_CHECK_THROWS_WITH(expr, with, ...) DOCTEST_WARN_THROWS_WITH(,,) +#define DOCTEST_REQUIRE_THROWS_WITH(expr, with, ...) DOCTEST_WARN_THROWS_WITH(,,) +#define DOCTEST_WARN_THROWS_WITH_AS(expr, with, ex, ...) DOCTEST_WARN_THROWS_WITH(,,) +#define DOCTEST_CHECK_THROWS_WITH_AS(expr, with, ex, ...) DOCTEST_WARN_THROWS_WITH(,,) +#define DOCTEST_REQUIRE_THROWS_WITH_AS(expr, with, ex, ...) DOCTEST_WARN_THROWS_WITH(,,) + +#define DOCTEST_WARN_THROWS_WITH_MESSAGE(expr, with, ...) DOCTEST_WARN_THROWS_WITH(,,) +#define DOCTEST_CHECK_THROWS_WITH_MESSAGE(expr, with, ...) DOCTEST_WARN_THROWS_WITH(,,) +#define DOCTEST_REQUIRE_THROWS_WITH_MESSAGE(expr, with, ...) DOCTEST_WARN_THROWS_WITH(,,) +#define DOCTEST_WARN_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) DOCTEST_WARN_THROWS_WITH(,,) +#define DOCTEST_CHECK_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) DOCTEST_WARN_THROWS_WITH(,,) +#define DOCTEST_REQUIRE_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) DOCTEST_WARN_THROWS_WITH(,,) + +#define DOCTEST_WARN_THROWS(...) [&] { try { __VA_ARGS__; return false; } catch (...) { return true; } }() +#define DOCTEST_CHECK_THROWS(...) [&] { try { __VA_ARGS__; return false; } catch (...) { return true; } }() +#define DOCTEST_REQUIRE_THROWS(...) [&] { try { __VA_ARGS__; return false; } catch (...) { return true; } }() +#define DOCTEST_WARN_THROWS_AS(expr, ...) [&] { try { expr; } catch (__VA_ARGS__) { return true; } catch (...) { } return false; }() +#define DOCTEST_CHECK_THROWS_AS(expr, ...) [&] { try { expr; } catch (__VA_ARGS__) { return true; } catch (...) { } return false; }() +#define DOCTEST_REQUIRE_THROWS_AS(expr, ...) [&] { try { expr; } catch (__VA_ARGS__) { return true; } catch (...) { } return false; }() +#define DOCTEST_WARN_NOTHROW(...) [&] { try { __VA_ARGS__; return true; } catch (...) { return false; } }() +#define DOCTEST_CHECK_NOTHROW(...) [&] { try { __VA_ARGS__; return true; } catch (...) { return false; } }() +#define DOCTEST_REQUIRE_NOTHROW(...) [&] { try { __VA_ARGS__; return true; } catch (...) { return false; } }() + +#define DOCTEST_WARN_THROWS_MESSAGE(expr, ...) [&] { try { __VA_ARGS__; return false; } catch (...) { return true; } }() +#define DOCTEST_CHECK_THROWS_MESSAGE(expr, ...) [&] { try { __VA_ARGS__; return false; } catch (...) { return true; } }() +#define DOCTEST_REQUIRE_THROWS_MESSAGE(expr, ...) [&] { try { __VA_ARGS__; return false; } catch (...) { return true; } }() +#define DOCTEST_WARN_THROWS_AS_MESSAGE(expr, ex, ...) [&] { try { expr; } catch (__VA_ARGS__) { return true; } catch (...) { } return false; }() +#define DOCTEST_CHECK_THROWS_AS_MESSAGE(expr, ex, ...) [&] { try { expr; } catch (__VA_ARGS__) { return true; } catch (...) { } return false; }() +#define DOCTEST_REQUIRE_THROWS_AS_MESSAGE(expr, ex, ...) [&] { try { expr; } catch (__VA_ARGS__) { return true; } catch (...) { } return false; }() +#define DOCTEST_WARN_NOTHROW_MESSAGE(expr, ...) [&] { try { __VA_ARGS__; return true; } catch (...) { return false; } }() +#define DOCTEST_CHECK_NOTHROW_MESSAGE(expr, ...) [&] { try { __VA_ARGS__; return true; } catch (...) { return false; } }() +#define DOCTEST_REQUIRE_NOTHROW_MESSAGE(expr, ...) [&] { try { __VA_ARGS__; return true; } catch (...) { return false; } }() + +#endif // DOCTEST_CONFIG_NO_EXCEPTIONS + +#else // DOCTEST_CONFIG_EVALUATE_ASSERTS_EVEN_WHEN_DISABLED + +#define DOCTEST_WARN(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_CHECK(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_REQUIRE(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_WARN_FALSE(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_CHECK_FALSE(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_REQUIRE_FALSE(...) DOCTEST_FUNC_EMPTY + +#define DOCTEST_WARN_MESSAGE(cond, ...) DOCTEST_FUNC_EMPTY +#define DOCTEST_CHECK_MESSAGE(cond, ...) DOCTEST_FUNC_EMPTY +#define DOCTEST_REQUIRE_MESSAGE(cond, ...) DOCTEST_FUNC_EMPTY +#define DOCTEST_WARN_FALSE_MESSAGE(cond, ...) DOCTEST_FUNC_EMPTY +#define DOCTEST_CHECK_FALSE_MESSAGE(cond, ...) DOCTEST_FUNC_EMPTY +#define DOCTEST_REQUIRE_FALSE_MESSAGE(cond, ...) DOCTEST_FUNC_EMPTY + +#define DOCTEST_WARN_EQ(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_CHECK_EQ(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_REQUIRE_EQ(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_WARN_NE(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_CHECK_NE(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_REQUIRE_NE(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_WARN_GT(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_CHECK_GT(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_REQUIRE_GT(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_WARN_LT(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_CHECK_LT(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_REQUIRE_LT(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_WARN_GE(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_CHECK_GE(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_REQUIRE_GE(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_WARN_LE(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_CHECK_LE(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_REQUIRE_LE(...) DOCTEST_FUNC_EMPTY + +#define DOCTEST_WARN_UNARY(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_CHECK_UNARY(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_REQUIRE_UNARY(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_WARN_UNARY_FALSE(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_CHECK_UNARY_FALSE(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_REQUIRE_UNARY_FALSE(...) DOCTEST_FUNC_EMPTY + +#ifndef DOCTEST_CONFIG_NO_EXCEPTIONS + +#define DOCTEST_WARN_THROWS(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_CHECK_THROWS(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_REQUIRE_THROWS(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_WARN_THROWS_AS(expr, ...) DOCTEST_FUNC_EMPTY +#define DOCTEST_CHECK_THROWS_AS(expr, ...) DOCTEST_FUNC_EMPTY +#define DOCTEST_REQUIRE_THROWS_AS(expr, ...) DOCTEST_FUNC_EMPTY +#define DOCTEST_WARN_THROWS_WITH(expr, ...) DOCTEST_FUNC_EMPTY +#define DOCTEST_CHECK_THROWS_WITH(expr, ...) DOCTEST_FUNC_EMPTY +#define DOCTEST_REQUIRE_THROWS_WITH(expr, ...) DOCTEST_FUNC_EMPTY +#define DOCTEST_WARN_THROWS_WITH_AS(expr, with, ...) DOCTEST_FUNC_EMPTY +#define DOCTEST_CHECK_THROWS_WITH_AS(expr, with, ...) DOCTEST_FUNC_EMPTY +#define DOCTEST_REQUIRE_THROWS_WITH_AS(expr, with, ...) DOCTEST_FUNC_EMPTY +#define DOCTEST_WARN_NOTHROW(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_CHECK_NOTHROW(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_REQUIRE_NOTHROW(...) DOCTEST_FUNC_EMPTY + +#define DOCTEST_WARN_THROWS_MESSAGE(expr, ...) DOCTEST_FUNC_EMPTY +#define DOCTEST_CHECK_THROWS_MESSAGE(expr, ...) DOCTEST_FUNC_EMPTY +#define DOCTEST_REQUIRE_THROWS_MESSAGE(expr, ...) DOCTEST_FUNC_EMPTY +#define DOCTEST_WARN_THROWS_AS_MESSAGE(expr, ex, ...) DOCTEST_FUNC_EMPTY +#define DOCTEST_CHECK_THROWS_AS_MESSAGE(expr, ex, ...) DOCTEST_FUNC_EMPTY +#define DOCTEST_REQUIRE_THROWS_AS_MESSAGE(expr, ex, ...) DOCTEST_FUNC_EMPTY +#define DOCTEST_WARN_THROWS_WITH_MESSAGE(expr, with, ...) DOCTEST_FUNC_EMPTY +#define DOCTEST_CHECK_THROWS_WITH_MESSAGE(expr, with, ...) DOCTEST_FUNC_EMPTY +#define DOCTEST_REQUIRE_THROWS_WITH_MESSAGE(expr, with, ...) DOCTEST_FUNC_EMPTY +#define DOCTEST_WARN_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) DOCTEST_FUNC_EMPTY +#define DOCTEST_CHECK_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) DOCTEST_FUNC_EMPTY +#define DOCTEST_REQUIRE_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) DOCTEST_FUNC_EMPTY +#define DOCTEST_WARN_NOTHROW_MESSAGE(expr, ...) DOCTEST_FUNC_EMPTY +#define DOCTEST_CHECK_NOTHROW_MESSAGE(expr, ...) DOCTEST_FUNC_EMPTY +#define DOCTEST_REQUIRE_NOTHROW_MESSAGE(expr, ...) DOCTEST_FUNC_EMPTY + +#endif // DOCTEST_CONFIG_NO_EXCEPTIONS + +#endif // DOCTEST_CONFIG_EVALUATE_ASSERTS_EVEN_WHEN_DISABLED #endif // DOCTEST_CONFIG_DISABLE +#ifdef DOCTEST_CONFIG_NO_EXCEPTIONS + +#ifdef DOCTEST_CONFIG_NO_EXCEPTIONS_BUT_WITH_ALL_ASSERTS +#define DOCTEST_EXCEPTION_EMPTY_FUNC DOCTEST_FUNC_EMPTY +#else // DOCTEST_CONFIG_NO_EXCEPTIONS_BUT_WITH_ALL_ASSERTS +#define DOCTEST_EXCEPTION_EMPTY_FUNC [] { static_assert(false, "Exceptions are disabled! " \ + "Use DOCTEST_CONFIG_NO_EXCEPTIONS_BUT_WITH_ALL_ASSERTS if you want to compile with exceptions disabled."); return false; }() + +#undef DOCTEST_REQUIRE +#undef DOCTEST_REQUIRE_FALSE +#undef DOCTEST_REQUIRE_MESSAGE +#undef DOCTEST_REQUIRE_FALSE_MESSAGE +#undef DOCTEST_REQUIRE_EQ +#undef DOCTEST_REQUIRE_NE +#undef DOCTEST_REQUIRE_GT +#undef DOCTEST_REQUIRE_LT +#undef DOCTEST_REQUIRE_GE +#undef DOCTEST_REQUIRE_LE +#undef DOCTEST_REQUIRE_UNARY +#undef DOCTEST_REQUIRE_UNARY_FALSE + +#define DOCTEST_REQUIRE DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_REQUIRE_FALSE DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_REQUIRE_MESSAGE DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_REQUIRE_FALSE_MESSAGE DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_REQUIRE_EQ DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_REQUIRE_NE DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_REQUIRE_GT DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_REQUIRE_LT DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_REQUIRE_GE DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_REQUIRE_LE DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_REQUIRE_UNARY DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_REQUIRE_UNARY_FALSE DOCTEST_EXCEPTION_EMPTY_FUNC + +#endif // DOCTEST_CONFIG_NO_EXCEPTIONS_BUT_WITH_ALL_ASSERTS + +#define DOCTEST_WARN_THROWS(...) DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_CHECK_THROWS(...) DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_REQUIRE_THROWS(...) DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_WARN_THROWS_AS(expr, ...) DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_CHECK_THROWS_AS(expr, ...) DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_REQUIRE_THROWS_AS(expr, ...) DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_WARN_THROWS_WITH(expr, ...) DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_CHECK_THROWS_WITH(expr, ...) DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_REQUIRE_THROWS_WITH(expr, ...) DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_WARN_THROWS_WITH_AS(expr, with, ...) DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_CHECK_THROWS_WITH_AS(expr, with, ...) DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_REQUIRE_THROWS_WITH_AS(expr, with, ...) DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_WARN_NOTHROW(...) DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_CHECK_NOTHROW(...) DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_REQUIRE_NOTHROW(...) DOCTEST_EXCEPTION_EMPTY_FUNC + +#define DOCTEST_WARN_THROWS_MESSAGE(expr, ...) DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_CHECK_THROWS_MESSAGE(expr, ...) DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_REQUIRE_THROWS_MESSAGE(expr, ...) DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_WARN_THROWS_AS_MESSAGE(expr, ex, ...) DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_CHECK_THROWS_AS_MESSAGE(expr, ex, ...) DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_REQUIRE_THROWS_AS_MESSAGE(expr, ex, ...) DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_WARN_THROWS_WITH_MESSAGE(expr, with, ...) DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_CHECK_THROWS_WITH_MESSAGE(expr, with, ...) DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_REQUIRE_THROWS_WITH_MESSAGE(expr, with, ...) DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_WARN_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_CHECK_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_REQUIRE_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_WARN_NOTHROW_MESSAGE(expr, ...) DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_CHECK_NOTHROW_MESSAGE(expr, ...) DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_REQUIRE_NOTHROW_MESSAGE(expr, ...) DOCTEST_EXCEPTION_EMPTY_FUNC + +#endif // DOCTEST_CONFIG_NO_EXCEPTIONS + +// clang-format off +// KEPT FOR BACKWARDS COMPATIBILITY - FORWARDING TO THE RIGHT MACROS +#define DOCTEST_FAST_WARN_EQ DOCTEST_WARN_EQ +#define DOCTEST_FAST_CHECK_EQ DOCTEST_CHECK_EQ +#define DOCTEST_FAST_REQUIRE_EQ DOCTEST_REQUIRE_EQ +#define DOCTEST_FAST_WARN_NE DOCTEST_WARN_NE +#define DOCTEST_FAST_CHECK_NE DOCTEST_CHECK_NE +#define DOCTEST_FAST_REQUIRE_NE DOCTEST_REQUIRE_NE +#define DOCTEST_FAST_WARN_GT DOCTEST_WARN_GT +#define DOCTEST_FAST_CHECK_GT DOCTEST_CHECK_GT +#define DOCTEST_FAST_REQUIRE_GT DOCTEST_REQUIRE_GT +#define DOCTEST_FAST_WARN_LT DOCTEST_WARN_LT +#define DOCTEST_FAST_CHECK_LT DOCTEST_CHECK_LT +#define DOCTEST_FAST_REQUIRE_LT DOCTEST_REQUIRE_LT +#define DOCTEST_FAST_WARN_GE DOCTEST_WARN_GE +#define DOCTEST_FAST_CHECK_GE DOCTEST_CHECK_GE +#define DOCTEST_FAST_REQUIRE_GE DOCTEST_REQUIRE_GE +#define DOCTEST_FAST_WARN_LE DOCTEST_WARN_LE +#define DOCTEST_FAST_CHECK_LE DOCTEST_CHECK_LE +#define DOCTEST_FAST_REQUIRE_LE DOCTEST_REQUIRE_LE + +#define DOCTEST_FAST_WARN_UNARY DOCTEST_WARN_UNARY +#define DOCTEST_FAST_CHECK_UNARY DOCTEST_CHECK_UNARY +#define DOCTEST_FAST_REQUIRE_UNARY DOCTEST_REQUIRE_UNARY +#define DOCTEST_FAST_WARN_UNARY_FALSE DOCTEST_WARN_UNARY_FALSE +#define DOCTEST_FAST_CHECK_UNARY_FALSE DOCTEST_CHECK_UNARY_FALSE +#define DOCTEST_FAST_REQUIRE_UNARY_FALSE DOCTEST_REQUIRE_UNARY_FALSE + +#define DOCTEST_TEST_CASE_TEMPLATE_INSTANTIATE(id, ...) DOCTEST_TEST_CASE_TEMPLATE_INVOKE(id,__VA_ARGS__) +// clang-format on + // BDD style macros // clang-format off -#define DOCTEST_SCENARIO(name) TEST_CASE(" Scenario: " name) -#ifdef DOCTEST_CONFIG_WITH_VARIADIC_MACROS -#define DOCTEST_SCENARIO_TEMPLATE(name, T, ...) TEST_CASE_TEMPLATE(" Scenario: " name, T, __VA_ARGS__) -#else // DOCTEST_CONFIG_WITH_VARIADIC_MACROS -#define DOCTEST_SCENARIO_TEMPLATE(name, T, types) TEST_CASE_TEMPLATE(" Scenario: " name, T, types) -#endif // DOCTEST_CONFIG_WITH_VARIADIC_MACROS +#define DOCTEST_SCENARIO(name) DOCTEST_TEST_CASE(" Scenario: " name) +#define DOCTEST_SCENARIO_CLASS(name) DOCTEST_TEST_CASE_CLASS(" Scenario: " name) +#define DOCTEST_SCENARIO_TEMPLATE(name, T, ...) DOCTEST_TEST_CASE_TEMPLATE(" Scenario: " name, T, __VA_ARGS__) #define DOCTEST_SCENARIO_TEMPLATE_DEFINE(name, T, id) DOCTEST_TEST_CASE_TEMPLATE_DEFINE(" Scenario: " name, T, id) -#define DOCTEST_GIVEN(name) SUBCASE(" Given: " name) -#define DOCTEST_WHEN(name) SUBCASE(" When: " name) -#define DOCTEST_AND_WHEN(name) SUBCASE("And when: " name) -#define DOCTEST_THEN(name) SUBCASE(" Then: " name) -#define DOCTEST_AND_THEN(name) SUBCASE(" And: " name) +#define DOCTEST_GIVEN(name) DOCTEST_SUBCASE(" Given: " name) +#define DOCTEST_WHEN(name) DOCTEST_SUBCASE(" When: " name) +#define DOCTEST_AND_WHEN(name) DOCTEST_SUBCASE("And when: " name) +#define DOCTEST_THEN(name) DOCTEST_SUBCASE(" Then: " name) +#define DOCTEST_AND_THEN(name) DOCTEST_SUBCASE(" And: " name) // clang-format on // == SHORT VERSIONS OF THE MACROS -#if !defined(DOCTEST_CONFIG_NO_SHORT_MACRO_NAMES) - -#define TEST_CASE DOCTEST_TEST_CASE -#define TEST_CASE_FIXTURE DOCTEST_TEST_CASE_FIXTURE -#define TYPE_TO_STRING DOCTEST_TYPE_TO_STRING -#define TEST_CASE_TEMPLATE DOCTEST_TEST_CASE_TEMPLATE -#define TEST_CASE_TEMPLATE_DEFINE DOCTEST_TEST_CASE_TEMPLATE_DEFINE -#define TEST_CASE_TEMPLATE_INSTANTIATE DOCTEST_TEST_CASE_TEMPLATE_INSTANTIATE -#define SUBCASE DOCTEST_SUBCASE -#define TEST_SUITE DOCTEST_TEST_SUITE -#define TEST_SUITE_BEGIN DOCTEST_TEST_SUITE_BEGIN +#ifndef DOCTEST_CONFIG_NO_SHORT_MACRO_NAMES + +#define TEST_CASE(name) DOCTEST_TEST_CASE(name) +#define TEST_CASE_CLASS(name) DOCTEST_TEST_CASE_CLASS(name) +#define TEST_CASE_FIXTURE(x, name) DOCTEST_TEST_CASE_FIXTURE(x, name) +#define TYPE_TO_STRING_AS(str, ...) DOCTEST_TYPE_TO_STRING_AS(str, __VA_ARGS__) +#define TYPE_TO_STRING(...) DOCTEST_TYPE_TO_STRING(__VA_ARGS__) +#define TEST_CASE_TEMPLATE(name, T, ...) DOCTEST_TEST_CASE_TEMPLATE(name, T, __VA_ARGS__) +#define TEST_CASE_TEMPLATE_DEFINE(name, T, id) DOCTEST_TEST_CASE_TEMPLATE_DEFINE(name, T, id) +#define TEST_CASE_TEMPLATE_INVOKE(id, ...) DOCTEST_TEST_CASE_TEMPLATE_INVOKE(id, __VA_ARGS__) +#define TEST_CASE_TEMPLATE_APPLY(id, ...) DOCTEST_TEST_CASE_TEMPLATE_APPLY(id, __VA_ARGS__) +#define SUBCASE(name) DOCTEST_SUBCASE(name) +#define TEST_SUITE(decorators) DOCTEST_TEST_SUITE(decorators) +#define TEST_SUITE_BEGIN(name) DOCTEST_TEST_SUITE_BEGIN(name) #define TEST_SUITE_END DOCTEST_TEST_SUITE_END -#define REGISTER_EXCEPTION_TRANSLATOR DOCTEST_REGISTER_EXCEPTION_TRANSLATOR -#define INFO DOCTEST_INFO -#define CAPTURE DOCTEST_CAPTURE -#define ADD_MESSAGE_AT DOCTEST_ADD_MESSAGE_AT -#define ADD_FAIL_CHECK_AT DOCTEST_ADD_FAIL_CHECK_AT -#define ADD_FAIL_AT DOCTEST_ADD_FAIL_AT -#define MESSAGE DOCTEST_MESSAGE -#define FAIL_CHECK DOCTEST_FAIL_CHECK -#define FAIL DOCTEST_FAIL -#define TO_LVALUE DOCTEST_TO_LVALUE - -#define WARN DOCTEST_WARN -#define WARN_FALSE DOCTEST_WARN_FALSE -#define WARN_THROWS DOCTEST_WARN_THROWS -#define WARN_THROWS_AS DOCTEST_WARN_THROWS_AS -#define WARN_NOTHROW DOCTEST_WARN_NOTHROW -#define CHECK DOCTEST_CHECK -#define CHECK_FALSE DOCTEST_CHECK_FALSE -#define CHECK_THROWS DOCTEST_CHECK_THROWS -#define CHECK_THROWS_AS DOCTEST_CHECK_THROWS_AS -#define CHECK_NOTHROW DOCTEST_CHECK_NOTHROW -#define REQUIRE DOCTEST_REQUIRE -#define REQUIRE_FALSE DOCTEST_REQUIRE_FALSE -#define REQUIRE_THROWS DOCTEST_REQUIRE_THROWS -#define REQUIRE_THROWS_AS DOCTEST_REQUIRE_THROWS_AS -#define REQUIRE_NOTHROW DOCTEST_REQUIRE_NOTHROW - -#define WARN_MESSAGE DOCTEST_WARN_MESSAGE -#define WARN_FALSE_MESSAGE DOCTEST_WARN_FALSE_MESSAGE -#define WARN_THROWS_MESSAGE DOCTEST_WARN_THROWS_MESSAGE -#define WARN_THROWS_AS_MESSAGE DOCTEST_WARN_THROWS_AS_MESSAGE -#define WARN_NOTHROW_MESSAGE DOCTEST_WARN_NOTHROW_MESSAGE -#define CHECK_MESSAGE DOCTEST_CHECK_MESSAGE -#define CHECK_FALSE_MESSAGE DOCTEST_CHECK_FALSE_MESSAGE -#define CHECK_THROWS_MESSAGE DOCTEST_CHECK_THROWS_MESSAGE -#define CHECK_THROWS_AS_MESSAGE DOCTEST_CHECK_THROWS_AS_MESSAGE -#define CHECK_NOTHROW_MESSAGE DOCTEST_CHECK_NOTHROW_MESSAGE -#define REQUIRE_MESSAGE DOCTEST_REQUIRE_MESSAGE -#define REQUIRE_FALSE_MESSAGE DOCTEST_REQUIRE_FALSE_MESSAGE -#define REQUIRE_THROWS_MESSAGE DOCTEST_REQUIRE_THROWS_MESSAGE -#define REQUIRE_THROWS_AS_MESSAGE DOCTEST_REQUIRE_THROWS_AS_MESSAGE -#define REQUIRE_NOTHROW_MESSAGE DOCTEST_REQUIRE_NOTHROW_MESSAGE - -#define SCENARIO DOCTEST_SCENARIO -#define SCENARIO_TEMPLATE DOCTEST_SCENARIO_TEMPLATE -#define SCENARIO_TEMPLATE_DEFINE DOCTEST_SCENARIO_TEMPLATE_DEFINE -#define GIVEN DOCTEST_GIVEN -#define WHEN DOCTEST_WHEN -#define AND_WHEN DOCTEST_AND_WHEN -#define THEN DOCTEST_THEN -#define AND_THEN DOCTEST_AND_THEN - -#define WARN_EQ DOCTEST_WARN_EQ -#define CHECK_EQ DOCTEST_CHECK_EQ -#define REQUIRE_EQ DOCTEST_REQUIRE_EQ -#define WARN_NE DOCTEST_WARN_NE -#define CHECK_NE DOCTEST_CHECK_NE -#define REQUIRE_NE DOCTEST_REQUIRE_NE -#define WARN_GT DOCTEST_WARN_GT -#define CHECK_GT DOCTEST_CHECK_GT -#define REQUIRE_GT DOCTEST_REQUIRE_GT -#define WARN_LT DOCTEST_WARN_LT -#define CHECK_LT DOCTEST_CHECK_LT -#define REQUIRE_LT DOCTEST_REQUIRE_LT -#define WARN_GE DOCTEST_WARN_GE -#define CHECK_GE DOCTEST_CHECK_GE -#define REQUIRE_GE DOCTEST_REQUIRE_GE -#define WARN_LE DOCTEST_WARN_LE -#define CHECK_LE DOCTEST_CHECK_LE -#define REQUIRE_LE DOCTEST_REQUIRE_LE -#define WARN_UNARY DOCTEST_WARN_UNARY -#define CHECK_UNARY DOCTEST_CHECK_UNARY -#define REQUIRE_UNARY DOCTEST_REQUIRE_UNARY -#define WARN_UNARY_FALSE DOCTEST_WARN_UNARY_FALSE -#define CHECK_UNARY_FALSE DOCTEST_CHECK_UNARY_FALSE -#define REQUIRE_UNARY_FALSE DOCTEST_REQUIRE_UNARY_FALSE - -#define FAST_WARN_EQ DOCTEST_FAST_WARN_EQ -#define FAST_CHECK_EQ DOCTEST_FAST_CHECK_EQ -#define FAST_REQUIRE_EQ DOCTEST_FAST_REQUIRE_EQ -#define FAST_WARN_NE DOCTEST_FAST_WARN_NE -#define FAST_CHECK_NE DOCTEST_FAST_CHECK_NE -#define FAST_REQUIRE_NE DOCTEST_FAST_REQUIRE_NE -#define FAST_WARN_GT DOCTEST_FAST_WARN_GT -#define FAST_CHECK_GT DOCTEST_FAST_CHECK_GT -#define FAST_REQUIRE_GT DOCTEST_FAST_REQUIRE_GT -#define FAST_WARN_LT DOCTEST_FAST_WARN_LT -#define FAST_CHECK_LT DOCTEST_FAST_CHECK_LT -#define FAST_REQUIRE_LT DOCTEST_FAST_REQUIRE_LT -#define FAST_WARN_GE DOCTEST_FAST_WARN_GE -#define FAST_CHECK_GE DOCTEST_FAST_CHECK_GE -#define FAST_REQUIRE_GE DOCTEST_FAST_REQUIRE_GE -#define FAST_WARN_LE DOCTEST_FAST_WARN_LE -#define FAST_CHECK_LE DOCTEST_FAST_CHECK_LE -#define FAST_REQUIRE_LE DOCTEST_FAST_REQUIRE_LE -#define FAST_WARN_UNARY DOCTEST_FAST_WARN_UNARY -#define FAST_CHECK_UNARY DOCTEST_FAST_CHECK_UNARY -#define FAST_REQUIRE_UNARY DOCTEST_FAST_REQUIRE_UNARY -#define FAST_WARN_UNARY_FALSE DOCTEST_FAST_WARN_UNARY_FALSE -#define FAST_CHECK_UNARY_FALSE DOCTEST_FAST_CHECK_UNARY_FALSE -#define FAST_REQUIRE_UNARY_FALSE DOCTEST_FAST_REQUIRE_UNARY_FALSE +#define REGISTER_EXCEPTION_TRANSLATOR(signature) DOCTEST_REGISTER_EXCEPTION_TRANSLATOR(signature) +#define REGISTER_REPORTER(name, priority, reporter) DOCTEST_REGISTER_REPORTER(name, priority, reporter) +#define REGISTER_LISTENER(name, priority, reporter) DOCTEST_REGISTER_LISTENER(name, priority, reporter) +#define INFO(...) DOCTEST_INFO(__VA_ARGS__) +#define CAPTURE(x) DOCTEST_CAPTURE(x) +#define ADD_MESSAGE_AT(file, line, ...) DOCTEST_ADD_MESSAGE_AT(file, line, __VA_ARGS__) +#define ADD_FAIL_CHECK_AT(file, line, ...) DOCTEST_ADD_FAIL_CHECK_AT(file, line, __VA_ARGS__) +#define ADD_FAIL_AT(file, line, ...) DOCTEST_ADD_FAIL_AT(file, line, __VA_ARGS__) +#define MESSAGE(...) DOCTEST_MESSAGE(__VA_ARGS__) +#define FAIL_CHECK(...) DOCTEST_FAIL_CHECK(__VA_ARGS__) +#define FAIL(...) DOCTEST_FAIL(__VA_ARGS__) +#define TO_LVALUE(...) DOCTEST_TO_LVALUE(__VA_ARGS__) + +#define WARN(...) DOCTEST_WARN(__VA_ARGS__) +#define WARN_FALSE(...) DOCTEST_WARN_FALSE(__VA_ARGS__) +#define WARN_THROWS(...) DOCTEST_WARN_THROWS(__VA_ARGS__) +#define WARN_THROWS_AS(expr, ...) DOCTEST_WARN_THROWS_AS(expr, __VA_ARGS__) +#define WARN_THROWS_WITH(expr, ...) DOCTEST_WARN_THROWS_WITH(expr, __VA_ARGS__) +#define WARN_THROWS_WITH_AS(expr, with, ...) DOCTEST_WARN_THROWS_WITH_AS(expr, with, __VA_ARGS__) +#define WARN_NOTHROW(...) DOCTEST_WARN_NOTHROW(__VA_ARGS__) +#define CHECK(...) DOCTEST_CHECK(__VA_ARGS__) +#define CHECK_FALSE(...) DOCTEST_CHECK_FALSE(__VA_ARGS__) +#define CHECK_THROWS(...) DOCTEST_CHECK_THROWS(__VA_ARGS__) +#define CHECK_THROWS_AS(expr, ...) DOCTEST_CHECK_THROWS_AS(expr, __VA_ARGS__) +#define CHECK_THROWS_WITH(expr, ...) DOCTEST_CHECK_THROWS_WITH(expr, __VA_ARGS__) +#define CHECK_THROWS_WITH_AS(expr, with, ...) DOCTEST_CHECK_THROWS_WITH_AS(expr, with, __VA_ARGS__) +#define CHECK_NOTHROW(...) DOCTEST_CHECK_NOTHROW(__VA_ARGS__) +#define REQUIRE(...) DOCTEST_REQUIRE(__VA_ARGS__) +#define REQUIRE_FALSE(...) DOCTEST_REQUIRE_FALSE(__VA_ARGS__) +#define REQUIRE_THROWS(...) DOCTEST_REQUIRE_THROWS(__VA_ARGS__) +#define REQUIRE_THROWS_AS(expr, ...) DOCTEST_REQUIRE_THROWS_AS(expr, __VA_ARGS__) +#define REQUIRE_THROWS_WITH(expr, ...) DOCTEST_REQUIRE_THROWS_WITH(expr, __VA_ARGS__) +#define REQUIRE_THROWS_WITH_AS(expr, with, ...) DOCTEST_REQUIRE_THROWS_WITH_AS(expr, with, __VA_ARGS__) +#define REQUIRE_NOTHROW(...) DOCTEST_REQUIRE_NOTHROW(__VA_ARGS__) + +#define WARN_MESSAGE(cond, ...) DOCTEST_WARN_MESSAGE(cond, __VA_ARGS__) +#define WARN_FALSE_MESSAGE(cond, ...) DOCTEST_WARN_FALSE_MESSAGE(cond, __VA_ARGS__) +#define WARN_THROWS_MESSAGE(expr, ...) DOCTEST_WARN_THROWS_MESSAGE(expr, __VA_ARGS__) +#define WARN_THROWS_AS_MESSAGE(expr, ex, ...) DOCTEST_WARN_THROWS_AS_MESSAGE(expr, ex, __VA_ARGS__) +#define WARN_THROWS_WITH_MESSAGE(expr, with, ...) DOCTEST_WARN_THROWS_WITH_MESSAGE(expr, with, __VA_ARGS__) +#define WARN_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) DOCTEST_WARN_THROWS_WITH_AS_MESSAGE(expr, with, ex, __VA_ARGS__) +#define WARN_NOTHROW_MESSAGE(expr, ...) DOCTEST_WARN_NOTHROW_MESSAGE(expr, __VA_ARGS__) +#define CHECK_MESSAGE(cond, ...) DOCTEST_CHECK_MESSAGE(cond, __VA_ARGS__) +#define CHECK_FALSE_MESSAGE(cond, ...) DOCTEST_CHECK_FALSE_MESSAGE(cond, __VA_ARGS__) +#define CHECK_THROWS_MESSAGE(expr, ...) DOCTEST_CHECK_THROWS_MESSAGE(expr, __VA_ARGS__) +#define CHECK_THROWS_AS_MESSAGE(expr, ex, ...) DOCTEST_CHECK_THROWS_AS_MESSAGE(expr, ex, __VA_ARGS__) +#define CHECK_THROWS_WITH_MESSAGE(expr, with, ...) DOCTEST_CHECK_THROWS_WITH_MESSAGE(expr, with, __VA_ARGS__) +#define CHECK_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) DOCTEST_CHECK_THROWS_WITH_AS_MESSAGE(expr, with, ex, __VA_ARGS__) +#define CHECK_NOTHROW_MESSAGE(expr, ...) DOCTEST_CHECK_NOTHROW_MESSAGE(expr, __VA_ARGS__) +#define REQUIRE_MESSAGE(cond, ...) DOCTEST_REQUIRE_MESSAGE(cond, __VA_ARGS__) +#define REQUIRE_FALSE_MESSAGE(cond, ...) DOCTEST_REQUIRE_FALSE_MESSAGE(cond, __VA_ARGS__) +#define REQUIRE_THROWS_MESSAGE(expr, ...) DOCTEST_REQUIRE_THROWS_MESSAGE(expr, __VA_ARGS__) +#define REQUIRE_THROWS_AS_MESSAGE(expr, ex, ...) DOCTEST_REQUIRE_THROWS_AS_MESSAGE(expr, ex, __VA_ARGS__) +#define REQUIRE_THROWS_WITH_MESSAGE(expr, with, ...) DOCTEST_REQUIRE_THROWS_WITH_MESSAGE(expr, with, __VA_ARGS__) +#define REQUIRE_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) DOCTEST_REQUIRE_THROWS_WITH_AS_MESSAGE(expr, with, ex, __VA_ARGS__) +#define REQUIRE_NOTHROW_MESSAGE(expr, ...) DOCTEST_REQUIRE_NOTHROW_MESSAGE(expr, __VA_ARGS__) + +#define SCENARIO(name) DOCTEST_SCENARIO(name) +#define SCENARIO_CLASS(name) DOCTEST_SCENARIO_CLASS(name) +#define SCENARIO_TEMPLATE(name, T, ...) DOCTEST_SCENARIO_TEMPLATE(name, T, __VA_ARGS__) +#define SCENARIO_TEMPLATE_DEFINE(name, T, id) DOCTEST_SCENARIO_TEMPLATE_DEFINE(name, T, id) +#define GIVEN(name) DOCTEST_GIVEN(name) +#define WHEN(name) DOCTEST_WHEN(name) +#define AND_WHEN(name) DOCTEST_AND_WHEN(name) +#define THEN(name) DOCTEST_THEN(name) +#define AND_THEN(name) DOCTEST_AND_THEN(name) + +#define WARN_EQ(...) DOCTEST_WARN_EQ(__VA_ARGS__) +#define CHECK_EQ(...) DOCTEST_CHECK_EQ(__VA_ARGS__) +#define REQUIRE_EQ(...) DOCTEST_REQUIRE_EQ(__VA_ARGS__) +#define WARN_NE(...) DOCTEST_WARN_NE(__VA_ARGS__) +#define CHECK_NE(...) DOCTEST_CHECK_NE(__VA_ARGS__) +#define REQUIRE_NE(...) DOCTEST_REQUIRE_NE(__VA_ARGS__) +#define WARN_GT(...) DOCTEST_WARN_GT(__VA_ARGS__) +#define CHECK_GT(...) DOCTEST_CHECK_GT(__VA_ARGS__) +#define REQUIRE_GT(...) DOCTEST_REQUIRE_GT(__VA_ARGS__) +#define WARN_LT(...) DOCTEST_WARN_LT(__VA_ARGS__) +#define CHECK_LT(...) DOCTEST_CHECK_LT(__VA_ARGS__) +#define REQUIRE_LT(...) DOCTEST_REQUIRE_LT(__VA_ARGS__) +#define WARN_GE(...) DOCTEST_WARN_GE(__VA_ARGS__) +#define CHECK_GE(...) DOCTEST_CHECK_GE(__VA_ARGS__) +#define REQUIRE_GE(...) DOCTEST_REQUIRE_GE(__VA_ARGS__) +#define WARN_LE(...) DOCTEST_WARN_LE(__VA_ARGS__) +#define CHECK_LE(...) DOCTEST_CHECK_LE(__VA_ARGS__) +#define REQUIRE_LE(...) DOCTEST_REQUIRE_LE(__VA_ARGS__) +#define WARN_UNARY(...) DOCTEST_WARN_UNARY(__VA_ARGS__) +#define CHECK_UNARY(...) DOCTEST_CHECK_UNARY(__VA_ARGS__) +#define REQUIRE_UNARY(...) DOCTEST_REQUIRE_UNARY(__VA_ARGS__) +#define WARN_UNARY_FALSE(...) DOCTEST_WARN_UNARY_FALSE(__VA_ARGS__) +#define CHECK_UNARY_FALSE(...) DOCTEST_CHECK_UNARY_FALSE(__VA_ARGS__) +#define REQUIRE_UNARY_FALSE(...) DOCTEST_REQUIRE_UNARY_FALSE(__VA_ARGS__) + +// KEPT FOR BACKWARDS COMPATIBILITY +#define FAST_WARN_EQ(...) DOCTEST_FAST_WARN_EQ(__VA_ARGS__) +#define FAST_CHECK_EQ(...) DOCTEST_FAST_CHECK_EQ(__VA_ARGS__) +#define FAST_REQUIRE_EQ(...) DOCTEST_FAST_REQUIRE_EQ(__VA_ARGS__) +#define FAST_WARN_NE(...) DOCTEST_FAST_WARN_NE(__VA_ARGS__) +#define FAST_CHECK_NE(...) DOCTEST_FAST_CHECK_NE(__VA_ARGS__) +#define FAST_REQUIRE_NE(...) DOCTEST_FAST_REQUIRE_NE(__VA_ARGS__) +#define FAST_WARN_GT(...) DOCTEST_FAST_WARN_GT(__VA_ARGS__) +#define FAST_CHECK_GT(...) DOCTEST_FAST_CHECK_GT(__VA_ARGS__) +#define FAST_REQUIRE_GT(...) DOCTEST_FAST_REQUIRE_GT(__VA_ARGS__) +#define FAST_WARN_LT(...) DOCTEST_FAST_WARN_LT(__VA_ARGS__) +#define FAST_CHECK_LT(...) DOCTEST_FAST_CHECK_LT(__VA_ARGS__) +#define FAST_REQUIRE_LT(...) DOCTEST_FAST_REQUIRE_LT(__VA_ARGS__) +#define FAST_WARN_GE(...) DOCTEST_FAST_WARN_GE(__VA_ARGS__) +#define FAST_CHECK_GE(...) DOCTEST_FAST_CHECK_GE(__VA_ARGS__) +#define FAST_REQUIRE_GE(...) DOCTEST_FAST_REQUIRE_GE(__VA_ARGS__) +#define FAST_WARN_LE(...) DOCTEST_FAST_WARN_LE(__VA_ARGS__) +#define FAST_CHECK_LE(...) DOCTEST_FAST_CHECK_LE(__VA_ARGS__) +#define FAST_REQUIRE_LE(...) DOCTEST_FAST_REQUIRE_LE(__VA_ARGS__) + +#define FAST_WARN_UNARY(...) DOCTEST_FAST_WARN_UNARY(__VA_ARGS__) +#define FAST_CHECK_UNARY(...) DOCTEST_FAST_CHECK_UNARY(__VA_ARGS__) +#define FAST_REQUIRE_UNARY(...) DOCTEST_FAST_REQUIRE_UNARY(__VA_ARGS__) +#define FAST_WARN_UNARY_FALSE(...) DOCTEST_FAST_WARN_UNARY_FALSE(__VA_ARGS__) +#define FAST_CHECK_UNARY_FALSE(...) DOCTEST_FAST_CHECK_UNARY_FALSE(__VA_ARGS__) +#define FAST_REQUIRE_UNARY_FALSE(...) DOCTEST_FAST_REQUIRE_UNARY_FALSE(__VA_ARGS__) + +#define TEST_CASE_TEMPLATE_INSTANTIATE(id, ...) DOCTEST_TEST_CASE_TEMPLATE_INSTANTIATE(id, __VA_ARGS__) #endif // DOCTEST_CONFIG_NO_SHORT_MACRO_NAMES +#ifndef DOCTEST_CONFIG_DISABLE + // this is here to clear the 'current test suite' for the current translation unit - at the top DOCTEST_TEST_SUITE_END(); -// add stringification for primitive/fundamental types -namespace doctest -{ -namespace detail -{ - DOCTEST_TYPE_TO_STRING_IMPL(bool) - DOCTEST_TYPE_TO_STRING_IMPL(float) - DOCTEST_TYPE_TO_STRING_IMPL(double) - DOCTEST_TYPE_TO_STRING_IMPL(long double) - DOCTEST_TYPE_TO_STRING_IMPL(char) - DOCTEST_TYPE_TO_STRING_IMPL(signed char) - DOCTEST_TYPE_TO_STRING_IMPL(unsigned char) - DOCTEST_TYPE_TO_STRING_IMPL(wchar_t) - DOCTEST_TYPE_TO_STRING_IMPL(short int) - DOCTEST_TYPE_TO_STRING_IMPL(unsigned short int) - DOCTEST_TYPE_TO_STRING_IMPL(int) - DOCTEST_TYPE_TO_STRING_IMPL(unsigned int) - DOCTEST_TYPE_TO_STRING_IMPL(long int) - DOCTEST_TYPE_TO_STRING_IMPL(unsigned long int) -#ifdef DOCTEST_CONFIG_WITH_LONG_LONG - DOCTEST_TYPE_TO_STRING_IMPL(long long int) - DOCTEST_TYPE_TO_STRING_IMPL(unsigned long long int) -#endif // DOCTEST_CONFIG_WITH_LONG_LONG -} // namespace detail -} // namespace doctest +#endif // DOCTEST_CONFIG_DISABLE DOCTEST_CLANG_SUPPRESS_WARNING_POP DOCTEST_MSVC_SUPPRESS_WARNING_POP DOCTEST_GCC_SUPPRESS_WARNING_POP +DOCTEST_SUPPRESS_COMMON_WARNINGS_POP + #endif // DOCTEST_LIBRARY_INCLUDED #ifndef DOCTEST_SINGLE_HEADER @@ -3162,19 +3047,23 @@ DOCTEST_GCC_SUPPRESS_WARNING_POP #endif // DOCTEST_SINGLE_HEADER #if defined(DOCTEST_CONFIG_IMPLEMENT) || !defined(DOCTEST_SINGLE_HEADER) -#ifndef DOCTEST_LIBRARY_IMPLEMENTATION -#define DOCTEST_LIBRARY_IMPLEMENTATION #ifndef DOCTEST_SINGLE_HEADER #include "doctest_fwd.h" #endif // DOCTEST_SINGLE_HEADER +DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wunused-macros") + +#ifndef DOCTEST_LIBRARY_IMPLEMENTATION +#define DOCTEST_LIBRARY_IMPLEMENTATION + +DOCTEST_CLANG_SUPPRESS_WARNING_POP + +DOCTEST_SUPPRESS_COMMON_WARNINGS_PUSH + DOCTEST_CLANG_SUPPRESS_WARNING_PUSH -DOCTEST_CLANG_SUPPRESS_WARNING("-Wunknown-pragmas") -DOCTEST_CLANG_SUPPRESS_WARNING("-Wpadded") DOCTEST_CLANG_SUPPRESS_WARNING("-Wglobal-constructors") DOCTEST_CLANG_SUPPRESS_WARNING("-Wexit-time-destructors") -DOCTEST_CLANG_SUPPRESS_WARNING("-Wmissing-prototypes") DOCTEST_CLANG_SUPPRESS_WARNING("-Wsign-conversion") DOCTEST_CLANG_SUPPRESS_WARNING("-Wshorten-64-to-32") DOCTEST_CLANG_SUPPRESS_WARNING("-Wmissing-variable-declarations") @@ -3182,88 +3071,43 @@ DOCTEST_CLANG_SUPPRESS_WARNING("-Wswitch") DOCTEST_CLANG_SUPPRESS_WARNING("-Wswitch-enum") DOCTEST_CLANG_SUPPRESS_WARNING("-Wcovered-switch-default") DOCTEST_CLANG_SUPPRESS_WARNING("-Wmissing-noreturn") -DOCTEST_CLANG_SUPPRESS_WARNING("-Wunused-local-typedef") DOCTEST_CLANG_SUPPRESS_WARNING("-Wdisabled-macro-expansion") DOCTEST_CLANG_SUPPRESS_WARNING("-Wmissing-braces") DOCTEST_CLANG_SUPPRESS_WARNING("-Wmissing-field-initializers") -DOCTEST_CLANG_SUPPRESS_WARNING("-Wc++11-long-long") -#if DOCTEST_CLANG && DOCTEST_CLANG_HAS_WARNING("-Wzero-as-null-pointer-constant") -DOCTEST_CLANG_SUPPRESS_WARNING("-Wzero-as-null-pointer-constant") -#endif // clang - 0 as null +DOCTEST_CLANG_SUPPRESS_WARNING("-Wunused-member-function") +DOCTEST_CLANG_SUPPRESS_WARNING("-Wnonportable-system-include-path") DOCTEST_GCC_SUPPRESS_WARNING_PUSH -DOCTEST_GCC_SUPPRESS_WARNING("-Wunknown-pragmas") -DOCTEST_GCC_SUPPRESS_WARNING("-Wpragmas") DOCTEST_GCC_SUPPRESS_WARNING("-Wconversion") -DOCTEST_GCC_SUPPRESS_WARNING("-Weffc++") DOCTEST_GCC_SUPPRESS_WARNING("-Wsign-conversion") -DOCTEST_GCC_SUPPRESS_WARNING("-Wstrict-overflow") DOCTEST_GCC_SUPPRESS_WARNING("-Wmissing-field-initializers") DOCTEST_GCC_SUPPRESS_WARNING("-Wmissing-braces") -DOCTEST_GCC_SUPPRESS_WARNING("-Wmissing-declarations") -DOCTEST_GCC_SUPPRESS_WARNING("-Winline") DOCTEST_GCC_SUPPRESS_WARNING("-Wswitch") DOCTEST_GCC_SUPPRESS_WARNING("-Wswitch-enum") DOCTEST_GCC_SUPPRESS_WARNING("-Wswitch-default") DOCTEST_GCC_SUPPRESS_WARNING("-Wunsafe-loop-optimizations") -DOCTEST_GCC_SUPPRESS_WARNING("-Wlong-long") DOCTEST_GCC_SUPPRESS_WARNING("-Wold-style-cast") -DOCTEST_GCC_SUPPRESS_WARNING("-Wzero-as-null-pointer-constant") -DOCTEST_GCC_SUPPRESS_WARNING("-Wunused-local-typedefs") -DOCTEST_GCC_SUPPRESS_WARNING("-Wuseless-cast") +DOCTEST_GCC_SUPPRESS_WARNING("-Wunused-function") +DOCTEST_GCC_SUPPRESS_WARNING("-Wmultiple-inheritance") +DOCTEST_GCC_SUPPRESS_WARNING("-Wsuggest-attribute") DOCTEST_MSVC_SUPPRESS_WARNING_PUSH -DOCTEST_MSVC_SUPPRESS_WARNING(4616) // invalid compiler warning -DOCTEST_MSVC_SUPPRESS_WARNING(4619) // invalid compiler warning -DOCTEST_MSVC_SUPPRESS_WARNING(4996) // The compiler encountered a deprecated declaration DOCTEST_MSVC_SUPPRESS_WARNING(4267) // 'var' : conversion from 'x' to 'y', possible loss of data -DOCTEST_MSVC_SUPPRESS_WARNING(4706) // assignment within conditional expression -DOCTEST_MSVC_SUPPRESS_WARNING(4512) // 'class' : assignment operator could not be generated -DOCTEST_MSVC_SUPPRESS_WARNING(4127) // conditional expression is constant DOCTEST_MSVC_SUPPRESS_WARNING(4530) // C++ exception handler used, but unwind semantics not enabled DOCTEST_MSVC_SUPPRESS_WARNING(4577) // 'noexcept' used with no exception handling mode specified DOCTEST_MSVC_SUPPRESS_WARNING(4774) // format string expected in argument is not a string literal DOCTEST_MSVC_SUPPRESS_WARNING(4365) // conversion from 'int' to 'unsigned', signed/unsigned mismatch -DOCTEST_MSVC_SUPPRESS_WARNING(4820) // padding in structs -DOCTEST_MSVC_SUPPRESS_WARNING(4640) // construction of local static object is not thread-safe DOCTEST_MSVC_SUPPRESS_WARNING(5039) // pointer to potentially throwing function passed to extern C -DOCTEST_MSVC_SUPPRESS_WARNING(5045) // Spectre mitigation stuff - -#if defined(DOCTEST_NO_CPP11_COMPAT) -DOCTEST_CLANG_SUPPRESS_WARNING("-Wc++98-compat") -DOCTEST_CLANG_SUPPRESS_WARNING("-Wc++98-compat-pedantic") -#endif // DOCTEST_NO_CPP11_COMPAT - -#define DOCTEST_LOG_START(s) \ - do { \ - if(!contextState->hasLoggedCurrentTestStart) { \ - logTestStart(s, *contextState->currentTest); \ - DOCTEST_PRINT_TO_OUTPUT_WINDOW_IN_IDE_BEGIN; \ - logTestStart(oss, *contextState->currentTest); \ - DOCTEST_PRINT_TO_OUTPUT_WINDOW_IN_IDE_END; \ - contextState->hasLoggedCurrentTestStart = true; \ - } \ - } while(false) - -#define DOCTEST_PRINT_TO_OUTPUT_WINDOW_IN_IDE_BEGIN \ - if(isDebuggerActive()) { \ - ContextState* p_cs = contextState; \ - bool with_col = p_cs->no_colors; \ - p_cs->no_colors = false; \ - std::ostringstream oss - -#define DOCTEST_PRINT_TO_OUTPUT_WINDOW_IN_IDE_END \ - printToDebugConsole(oss.str().c_str()); \ - p_cs->no_colors = with_col; \ - } \ - ((void)0) +DOCTEST_MSVC_SUPPRESS_WARNING(4800) // forcing value to bool 'true' or 'false' (performance warning) +DOCTEST_MSVC_SUPPRESS_WARNING(5245) // unreferenced function with internal linkage has been removed DOCTEST_MAKE_STD_HEADERS_CLEAN_FROM_WARNINGS_ON_WALL_BEGIN // required includes - will go only in one translation unit! #include #include -// borland (Embarcadero) compiler requires math.h and not cmath - https://github.com/onqtam/doctest/pull/37 +#include +// borland (Embarcadero) compiler requires math.h and not cmath - https://github.com/doctest/doctest/pull/37 #ifdef __BORLANDC__ #include #endif // __BORLANDC__ @@ -3273,29 +3117,142 @@ DOCTEST_MAKE_STD_HEADERS_CLEAN_FROM_WARNINGS_ON_WALL_BEGIN #include #include #include +#include #include #include #include #include #include +#ifndef DOCTEST_CONFIG_NO_MULTITHREADING +#include +#include +#define DOCTEST_DECLARE_MUTEX(name) std::mutex name; +#define DOCTEST_DECLARE_STATIC_MUTEX(name) static DOCTEST_DECLARE_MUTEX(name) +#define DOCTEST_LOCK_MUTEX(name) std::lock_guard DOCTEST_ANONYMOUS(DOCTEST_ANON_LOCK_)(name); +#else // DOCTEST_CONFIG_NO_MULTITHREADING +#define DOCTEST_DECLARE_MUTEX(name) +#define DOCTEST_DECLARE_STATIC_MUTEX(name) +#define DOCTEST_LOCK_MUTEX(name) +#endif // DOCTEST_CONFIG_NO_MULTITHREADING #include +#include +#include #include #include #include #include #include -#if !DOCTEST_MSVC -#include -#endif // !MSVC +#include +#include + +#ifdef DOCTEST_PLATFORM_MAC +#include +#include +#include +#endif // DOCTEST_PLATFORM_MAC + +#ifdef DOCTEST_PLATFORM_WINDOWS + +// defines for a leaner windows.h +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif // WIN32_LEAN_AND_MEAN +#ifndef NOMINMAX +#define NOMINMAX +#endif // NOMINMAX + +// not sure what AfxWin.h is for - here I do what Catch does +#ifdef __AFXDLL +#include +#else +#include +#endif +#include + +#else // DOCTEST_PLATFORM_WINDOWS + +#include +#include + +#endif // DOCTEST_PLATFORM_WINDOWS + +// this is a fix for https://github.com/doctest/doctest/issues/348 +// https://mail.gnome.org/archives/xml/2012-January/msg00000.html +#if !defined(HAVE_UNISTD_H) && !defined(STDOUT_FILENO) +#define STDOUT_FILENO fileno(stdout) +#endif // HAVE_UNISTD_H DOCTEST_MAKE_STD_HEADERS_CLEAN_FROM_WARNINGS_ON_WALL_END -namespace doctest -{ -namespace detail -{ +// counts the number of elements in a C array +#define DOCTEST_COUNTOF(x) (sizeof(x) / sizeof(x[0])) + +#ifdef DOCTEST_CONFIG_DISABLE +#define DOCTEST_BRANCH_ON_DISABLED(if_disabled, if_not_disabled) if_disabled +#else // DOCTEST_CONFIG_DISABLE +#define DOCTEST_BRANCH_ON_DISABLED(if_disabled, if_not_disabled) if_not_disabled +#endif // DOCTEST_CONFIG_DISABLE + +#ifndef DOCTEST_CONFIG_OPTIONS_PREFIX +#define DOCTEST_CONFIG_OPTIONS_PREFIX "dt-" +#endif + +#ifndef DOCTEST_THREAD_LOCAL +#if defined(DOCTEST_CONFIG_NO_MULTITHREADING) || DOCTEST_MSVC && (DOCTEST_MSVC < DOCTEST_COMPILER(19, 0, 0)) +#define DOCTEST_THREAD_LOCAL +#else // DOCTEST_MSVC +#define DOCTEST_THREAD_LOCAL thread_local +#endif // DOCTEST_MSVC +#endif // DOCTEST_THREAD_LOCAL + +#ifndef DOCTEST_MULTI_LANE_ATOMICS_THREAD_LANES +#define DOCTEST_MULTI_LANE_ATOMICS_THREAD_LANES 32 +#endif + +#ifndef DOCTEST_MULTI_LANE_ATOMICS_CACHE_LINE_SIZE +#define DOCTEST_MULTI_LANE_ATOMICS_CACHE_LINE_SIZE 64 +#endif + +#ifdef DOCTEST_CONFIG_NO_UNPREFIXED_OPTIONS +#define DOCTEST_OPTIONS_PREFIX_DISPLAY DOCTEST_CONFIG_OPTIONS_PREFIX +#else +#define DOCTEST_OPTIONS_PREFIX_DISPLAY "" +#endif + +#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) +#define DOCTEST_CONFIG_NO_MULTI_LANE_ATOMICS +#endif + +#ifndef DOCTEST_CDECL +#define DOCTEST_CDECL __cdecl +#endif + +namespace doctest { + +bool is_running_in_test = false; + +namespace { + using namespace detail; + + template + DOCTEST_NORETURN void throw_exception(Ex const& e) { +#ifndef DOCTEST_CONFIG_NO_EXCEPTIONS + throw e; +#else // DOCTEST_CONFIG_NO_EXCEPTIONS + std::cerr << "doctest will terminate because it needed to throw an exception.\n" + << "The message was: " << e.what() << '\n'; + std::terminate(); +#endif // DOCTEST_CONFIG_NO_EXCEPTIONS + } + +#ifndef DOCTEST_INTERNAL_ERROR +#define DOCTEST_INTERNAL_ERROR(msg) \ + throw_exception(std::logic_error( \ + __FILE__ ":" DOCTEST_TOSTR(__LINE__) ": Internal doctest error: " msg)) +#endif // DOCTEST_INTERNAL_ERROR + // case insensitive strcmp - int stricmp(char const* a, char const* b) { + int stricmp(const char* a, const char* b) { for(;; a++, b++) { const int d = tolower(*a) - tolower(*b); if(d != 0 || !*a) @@ -3303,22 +3260,6 @@ namespace detail } } - void my_memcpy(void* dest, const void* src, unsigned num) { memcpy(dest, src, num); } - - template - String fpToString(T value, int precision) { - std::ostringstream oss; - oss << std::setprecision(precision) << std::fixed << value; - std::string d = oss.str(); - size_t i = d.find_last_not_of('0'); - if(i != std::string::npos && i != d.size() - 1) { - if(d[i] == '.') - i++; - d = d.substr(0, i + 1); - } - return d.c_str(); - } - struct Endianness { enum Arch @@ -3328,155 +3269,353 @@ namespace detail }; static Arch which() { - union _ - { - int asInt; - char asChar[sizeof(int)]; - } u; - - u.asInt = 1; // NOLINT - return (u.asChar[sizeof(int) - 1] == 1) ? Big : Little; // NOLINT + int x = 1; + // casting any data pointer to char* is allowed + auto ptr = reinterpret_cast(&x); + if(*ptr) + return Little; + return Big; } }; +} // namespace - String rawMemoryToString(const void* object, unsigned size) { - // Reverse order for little endian architectures - int i = 0, end = static_cast(size), inc = 1; - if(Endianness::which() == Endianness::Little) { - i = end - 1; - end = inc = -1; +namespace detail { + DOCTEST_THREAD_LOCAL class + { + std::vector stack; + std::stringstream ss; + + public: + std::ostream* push() { + stack.push_back(ss.tellp()); + return &ss; + } + + String pop() { + if (stack.empty()) + DOCTEST_INTERNAL_ERROR("TLSS was empty when trying to pop!"); + + std::streampos pos = stack.back(); + stack.pop_back(); + unsigned sz = static_cast(ss.tellp() - pos); + ss.rdbuf()->pubseekpos(pos, std::ios::in | std::ios::out); + return String(ss, sz); } + } g_oss; - unsigned char const* bytes = static_cast(object); - std::ostringstream oss; - oss << "0x" << std::setfill('0') << std::hex; - for(; i != end; i += inc) - oss << std::setw(2) << static_cast(bytes[i]); - return oss.str().c_str(); + std::ostream* tlssPush() { + return g_oss.push(); } - std::ostream* createStream() { return new std::ostringstream(); } - String getStreamResult(std::ostream* s) { - return static_cast(s)->str().c_str(); // NOLINT + String tlssPop() { + return g_oss.pop(); } - void freeStream(std::ostream* s) { delete s; } #ifndef DOCTEST_CONFIG_DISABLE - // this holds both parameters for the command line and runtime data for tests - struct ContextState : TestAccessibleContextState //!OCLINT too many fields - { - // == parameters from the command line - - std::vector > filters; - - String order_by; // how tests should be ordered - unsigned rand_seed; // the seed for rand ordering - - unsigned first; // the first (matching) test to be executed - unsigned last; // the last (matching) test to be executed - - int abort_after; // stop tests after this many failed assertions - int subcase_filter_levels; // apply the subcase filters for the first N levels - bool case_sensitive; // if filtering should be case sensitive - bool exit; // if the program should be exited after the tests are ran/whatever - bool duration; // print the time duration of each test case - bool no_exitcode; // if the framework should return 0 as the exitcode - bool no_run; // to not run the tests at all (can be done with an "*" exclude) - bool no_version; // to not print the version of the framework - bool no_colors; // if output to the console should be colorized - bool force_colors; // forces the use of colors even when a tty cannot be detected - bool no_breaks; // to not break into the debugger - bool no_skip; // don't skip test cases which are marked to be skipped - bool gnu_file_line; // if line numbers should be surrounded with :x: and not (x): - bool no_path_in_filenames; // if the path to files should be removed from the output - bool no_line_numbers; // if source code line numbers should be omitted from the output - bool no_skipped_summary; // don't print "skipped" in the summary !!! UNDOCUMENTED !!! - - bool help; // to print the help - bool version; // to print the version - bool count; // if only the count of matching tests is to be retreived - bool list_test_cases; // to list all tests matching the filters - bool list_test_suites; // to list all suites matching the filters - - // == data for the tests being ran - - unsigned numTestsPassingFilters; - unsigned numTestSuitesPassingFilters; - unsigned numFailed; - const TestCase* currentTest; - bool hasLoggedCurrentTestStart; - int numAssertionsForCurrentTestcase; - int numAssertions; - int numFailedAssertionsForCurrentTestcase; - int numFailedAssertions; - bool hasCurrentTestFailed; - - std::vector contexts; // for logging with INFO() and friends - std::vector exceptionalContexts; // logging from INFO() due to an exception +namespace timer_large_integer +{ - // stuff for subcases - std::set subcasesPassed; - std::set subcasesEnteredLevels; - std::vector subcasesStack; - int subcasesCurrentLevel; - bool subcasesHasSkipped; +#if defined(DOCTEST_PLATFORM_WINDOWS) + using type = ULONGLONG; +#else // DOCTEST_PLATFORM_WINDOWS + using type = std::uint64_t; +#endif // DOCTEST_PLATFORM_WINDOWS +} - void resetRunData() { - numTestsPassingFilters = 0; - numTestSuitesPassingFilters = 0; - numFailed = 0; - numAssertions = 0; - numFailedAssertions = 0; - numFailedAssertionsForCurrentTestcase = 0; +using ticks_t = timer_large_integer::type; + +#ifdef DOCTEST_CONFIG_GETCURRENTTICKS + ticks_t getCurrentTicks() { return DOCTEST_CONFIG_GETCURRENTTICKS(); } +#elif defined(DOCTEST_PLATFORM_WINDOWS) + ticks_t getCurrentTicks() { + static LARGE_INTEGER hz = { {0} }, hzo = { {0} }; + if(!hz.QuadPart) { + QueryPerformanceFrequency(&hz); + QueryPerformanceCounter(&hzo); } + LARGE_INTEGER t; + QueryPerformanceCounter(&t); + return ((t.QuadPart - hzo.QuadPart) * LONGLONG(1000000)) / hz.QuadPart; + } +#else // DOCTEST_PLATFORM_WINDOWS + ticks_t getCurrentTicks() { + timeval t; + gettimeofday(&t, nullptr); + return static_cast(t.tv_sec) * 1000000 + static_cast(t.tv_usec); + } +#endif // DOCTEST_PLATFORM_WINDOWS - // cppcheck-suppress uninitMemberVar - ContextState() - : filters(8) // 8 different filters total - { - resetRunData(); + struct Timer + { + void start() { m_ticks = getCurrentTicks(); } + unsigned int getElapsedMicroseconds() const { + return static_cast(getCurrentTicks() - m_ticks); } - }; + //unsigned int getElapsedMilliseconds() const { + // return static_cast(getElapsedMicroseconds() / 1000); + //} + double getElapsedSeconds() const { return static_cast(getCurrentTicks() - m_ticks) / 1000000.0; } - ContextState* contextState = 0; -#endif // DOCTEST_CONFIG_DISABLE -} // namespace detail + private: + ticks_t m_ticks = 0; + }; -void String::copy(const String& other) { - if(other.isOnStack()) { - memcpy(buf, other.buf, len); - } else { - setOnHeap(); - data.size = other.data.size; - data.capacity = data.size + 1; - data.ptr = new char[data.capacity]; - memcpy(data.ptr, other.data.ptr, data.size + 1); - } -} +#ifdef DOCTEST_CONFIG_NO_MULTITHREADING + template + using Atomic = T; +#else // DOCTEST_CONFIG_NO_MULTITHREADING + template + using Atomic = std::atomic; +#endif // DOCTEST_CONFIG_NO_MULTITHREADING -String::String(const char* in) { - unsigned in_len = strlen(in); - if(in_len <= last) { - memcpy(buf, in, in_len + 1); - setLast(last - in_len); - } else { +#if defined(DOCTEST_CONFIG_NO_MULTI_LANE_ATOMICS) || defined(DOCTEST_CONFIG_NO_MULTITHREADING) + template + using MultiLaneAtomic = Atomic; +#else // DOCTEST_CONFIG_NO_MULTI_LANE_ATOMICS + // Provides a multilane implementation of an atomic variable that supports add, sub, load, + // store. Instead of using a single atomic variable, this splits up into multiple ones, + // each sitting on a separate cache line. The goal is to provide a speedup when most + // operations are modifying. It achieves this with two properties: + // + // * Multiple atomics are used, so chance of congestion from the same atomic is reduced. + // * Each atomic sits on a separate cache line, so false sharing is reduced. + // + // The disadvantage is that there is a small overhead due to the use of TLS, and load/store + // is slower because all atomics have to be accessed. + template + class MultiLaneAtomic + { + struct CacheLineAlignedAtomic + { + Atomic atomic{}; + char padding[DOCTEST_MULTI_LANE_ATOMICS_CACHE_LINE_SIZE - sizeof(Atomic)]; + }; + CacheLineAlignedAtomic m_atomics[DOCTEST_MULTI_LANE_ATOMICS_THREAD_LANES]; + + static_assert(sizeof(CacheLineAlignedAtomic) == DOCTEST_MULTI_LANE_ATOMICS_CACHE_LINE_SIZE, + "guarantee one atomic takes exactly one cache line"); + + public: + T operator++() DOCTEST_NOEXCEPT { return fetch_add(1) + 1; } + + T operator++(int) DOCTEST_NOEXCEPT { return fetch_add(1); } + + T fetch_add(T arg, std::memory_order order = std::memory_order_seq_cst) DOCTEST_NOEXCEPT { + return myAtomic().fetch_add(arg, order); + } + + T fetch_sub(T arg, std::memory_order order = std::memory_order_seq_cst) DOCTEST_NOEXCEPT { + return myAtomic().fetch_sub(arg, order); + } + + operator T() const DOCTEST_NOEXCEPT { return load(); } + + T load(std::memory_order order = std::memory_order_seq_cst) const DOCTEST_NOEXCEPT { + auto result = T(); + for(auto const& c : m_atomics) { + result += c.atomic.load(order); + } + return result; + } + + T operator=(T desired) DOCTEST_NOEXCEPT { // lgtm [cpp/assignment-does-not-return-this] + store(desired); + return desired; + } + + void store(T desired, std::memory_order order = std::memory_order_seq_cst) DOCTEST_NOEXCEPT { + // first value becomes desired", all others become 0. + for(auto& c : m_atomics) { + c.atomic.store(desired, order); + desired = {}; + } + } + + private: + // Each thread has a different atomic that it operates on. If more than NumLanes threads + // use this, some will use the same atomic. So performance will degrade a bit, but still + // everything will work. + // + // The logic here is a bit tricky. The call should be as fast as possible, so that there + // is minimal to no overhead in determining the correct atomic for the current thread. + // + // 1. A global static counter laneCounter counts continuously up. + // 2. Each successive thread will use modulo operation of that counter so it gets an atomic + // assigned in a round-robin fashion. + // 3. This tlsLaneIdx is stored in the thread local data, so it is directly available with + // little overhead. + Atomic& myAtomic() DOCTEST_NOEXCEPT { + static Atomic laneCounter; + DOCTEST_THREAD_LOCAL size_t tlsLaneIdx = + laneCounter++ % DOCTEST_MULTI_LANE_ATOMICS_THREAD_LANES; + + return m_atomics[tlsLaneIdx].atomic; + } + }; +#endif // DOCTEST_CONFIG_NO_MULTI_LANE_ATOMICS + + // this holds both parameters from the command line and runtime data for tests + struct ContextState : ContextOptions, TestRunStats, CurrentTestCaseStats + { + MultiLaneAtomic numAssertsCurrentTest_atomic; + MultiLaneAtomic numAssertsFailedCurrentTest_atomic; + + std::vector> filters = decltype(filters)(9); // 9 different filters + + std::vector reporters_currently_used; + + assert_handler ah = nullptr; + + Timer timer; + + std::vector stringifiedContexts; // logging from INFO() due to an exception + + // stuff for subcases + bool reachedLeaf; + std::vector subcaseStack; + std::vector nextSubcaseStack; + std::unordered_set fullyTraversedSubcases; + size_t currentSubcaseDepth; + Atomic shouldLogCurrentException; + + void resetRunData() { + numTestCases = 0; + numTestCasesPassingFilters = 0; + numTestSuitesPassingFilters = 0; + numTestCasesFailed = 0; + numAsserts = 0; + numAssertsFailed = 0; + numAssertsCurrentTest = 0; + numAssertsFailedCurrentTest = 0; + } + + void finalizeTestCaseData() { + seconds = timer.getElapsedSeconds(); + + // update the non-atomic counters + numAsserts += numAssertsCurrentTest_atomic; + numAssertsFailed += numAssertsFailedCurrentTest_atomic; + numAssertsCurrentTest = numAssertsCurrentTest_atomic; + numAssertsFailedCurrentTest = numAssertsFailedCurrentTest_atomic; + + if(numAssertsFailedCurrentTest) + failure_flags |= TestCaseFailureReason::AssertFailure; + + if(Approx(currentTest->m_timeout).epsilon(DBL_EPSILON) != 0 && + Approx(seconds).epsilon(DBL_EPSILON) > currentTest->m_timeout) + failure_flags |= TestCaseFailureReason::Timeout; + + if(currentTest->m_should_fail) { + if(failure_flags) { + failure_flags |= TestCaseFailureReason::ShouldHaveFailedAndDid; + } else { + failure_flags |= TestCaseFailureReason::ShouldHaveFailedButDidnt; + } + } else if(failure_flags && currentTest->m_may_fail) { + failure_flags |= TestCaseFailureReason::CouldHaveFailedAndDid; + } else if(currentTest->m_expected_failures > 0) { + if(numAssertsFailedCurrentTest == currentTest->m_expected_failures) { + failure_flags |= TestCaseFailureReason::FailedExactlyNumTimes; + } else { + failure_flags |= TestCaseFailureReason::DidntFailExactlyNumTimes; + } + } + + bool ok_to_fail = (TestCaseFailureReason::ShouldHaveFailedAndDid & failure_flags) || + (TestCaseFailureReason::CouldHaveFailedAndDid & failure_flags) || + (TestCaseFailureReason::FailedExactlyNumTimes & failure_flags); + + // if any subcase has failed - the whole test case has failed + testCaseSuccess = !(failure_flags && !ok_to_fail); + if(!testCaseSuccess) + numTestCasesFailed++; + } + }; + + ContextState* g_cs = nullptr; + + // used to avoid locks for the debug output + // TODO: figure out if this is indeed necessary/correct - seems like either there still + // could be a race or that there wouldn't be a race even if using the context directly + DOCTEST_THREAD_LOCAL bool g_no_colors; + +#endif // DOCTEST_CONFIG_DISABLE +} // namespace detail + +char* String::allocate(size_type sz) { + if (sz <= last) { + buf[sz] = '\0'; + setLast(last - sz); + return buf; + } else { setOnHeap(); - data.size = in_len; + data.size = sz; data.capacity = data.size + 1; - data.ptr = new char[data.capacity]; - memcpy(data.ptr, in, in_len + 1); + data.ptr = new char[data.capacity]; + data.ptr[sz] = '\0'; + return data.ptr; + } +} + +void String::setOnHeap() noexcept { *reinterpret_cast(&buf[last]) = 128; } +void String::setLast(size_type in) noexcept { buf[last] = char(in); } +void String::setSize(size_type sz) noexcept { + if (isOnStack()) { buf[sz] = '\0'; setLast(last - sz); } + else { data.ptr[sz] = '\0'; data.size = sz; } +} + +void String::copy(const String& other) { + if(other.isOnStack()) { + memcpy(buf, other.buf, len); + } else { + memcpy(allocate(other.data.size), other.data.ptr, other.data.size); + } +} + +String::String() noexcept { + buf[0] = '\0'; + setLast(); +} + +String::~String() { + if(!isOnStack()) + delete[] data.ptr; +} // NOLINT(clang-analyzer-cplusplus.NewDeleteLeaks) + +String::String(const char* in) + : String(in, strlen(in)) {} + +String::String(const char* in, size_type in_size) { + memcpy(allocate(in_size), in, in_size); +} + +String::String(std::istream& in, size_type in_size) { + in.read(allocate(in_size), in_size); +} + +String::String(const String& other) { copy(other); } + +String& String::operator=(const String& other) { + if(this != &other) { + if(!isOnStack()) + delete[] data.ptr; + + copy(other); } + + return *this; } String& String::operator+=(const String& other) { - const unsigned my_old_size = size(); - const unsigned other_size = other.size(); - const unsigned total_size = my_old_size + other_size; + const size_type my_old_size = size(); + const size_type other_size = other.size(); + const size_type total_size = my_old_size + other_size; if(isOnStack()) { if(total_size < len) { // append to the current stack space memcpy(buf + my_old_size, other.c_str(), other_size + 1); + // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks) setLast(last - total_size); } else { // alloc new chunk @@ -3518,14 +3657,13 @@ String& String::operator+=(const String& other) { return *this; } -#ifdef DOCTEST_CONFIG_WITH_RVALUE_REFERENCES -String::String(String&& other) { +String::String(String&& other) noexcept { memcpy(buf, other.buf, len); other.buf[0] = '\0'; other.setLast(); } -String& String::operator=(String&& other) { +String& String::operator=(String&& other) noexcept { if(this != &other) { if(!isOnStack()) delete[] data.ptr; @@ -3535,11 +3673,64 @@ String& String::operator=(String&& other) { } return *this; } -#endif // DOCTEST_CONFIG_WITH_RVALUE_REFERENCES + +char String::operator[](size_type i) const { + return const_cast(this)->operator[](i); +} + +char& String::operator[](size_type i) { + if(isOnStack()) + return reinterpret_cast(buf)[i]; + return data.ptr[i]; +} + +DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH("-Wmaybe-uninitialized") +String::size_type String::size() const { + if(isOnStack()) + return last - (size_type(buf[last]) & 31); // using "last" would work only if "len" is 32 + return data.size; +} +DOCTEST_GCC_SUPPRESS_WARNING_POP + +String::size_type String::capacity() const { + if(isOnStack()) + return len; + return data.capacity; +} + +String String::substr(size_type pos, size_type cnt) && { + cnt = std::min(cnt, size() - 1 - pos); + char* cptr = c_str(); + memmove(cptr, cptr + pos, cnt); + setSize(cnt); + return std::move(*this); +} + +String String::substr(size_type pos, size_type cnt) const & { + cnt = std::min(cnt, size() - 1 - pos); + return String{ c_str() + pos, cnt }; +} + +String::size_type String::find(char ch, size_type pos) const { + const char* begin = c_str(); + const char* end = begin + size(); + const char* it = begin + pos; + for (; it < end && *it != ch; it++); + if (it < end) { return static_cast(it - begin); } + else { return npos; } +} + +String::size_type String::rfind(char ch, size_type pos) const { + const char* begin = c_str(); + const char* it = begin + std::min(pos, size() - 1); + for (; it >= begin && *it != ch; it--); + if (it >= begin) { return static_cast(it - begin); } + else { return npos; } +} int String::compare(const char* other, bool no_case) const { if(no_case) - return detail::stricmp(c_str(), other); + return doctest::stricmp(c_str(), other); return std::strcmp(c_str(), other); } @@ -3547,116 +3738,258 @@ int String::compare(const String& other, bool no_case) const { return compare(other.c_str(), no_case); } +String operator+(const String& lhs, const String& rhs) { return String(lhs) += rhs; } + +bool operator==(const String& lhs, const String& rhs) { return lhs.compare(rhs) == 0; } +bool operator!=(const String& lhs, const String& rhs) { return lhs.compare(rhs) != 0; } +bool operator< (const String& lhs, const String& rhs) { return lhs.compare(rhs) < 0; } +bool operator> (const String& lhs, const String& rhs) { return lhs.compare(rhs) > 0; } +bool operator<=(const String& lhs, const String& rhs) { return (lhs != rhs) ? lhs.compare(rhs) < 0 : true; } +bool operator>=(const String& lhs, const String& rhs) { return (lhs != rhs) ? lhs.compare(rhs) > 0 : true; } + std::ostream& operator<<(std::ostream& s, const String& in) { return s << in.c_str(); } -Approx::Approx(double value) - : m_epsilon(static_cast(std::numeric_limits::epsilon()) * 100) - , m_scale(1.0) - , m_value(value) {} +Contains::Contains(const String& str) : string(str) { } -bool operator==(double lhs, Approx const& rhs) { - // Thanks to Richard Harris for his help refining this formula - return std::fabs(lhs - rhs.m_value) < - rhs.m_epsilon * (rhs.m_scale + std::max(std::fabs(lhs), std::fabs(rhs.m_value))); +bool Contains::checkWith(const String& other) const { + return strstr(other.c_str(), string.c_str()) != nullptr; } -String Approx::toString() const { return String("Approx( ") + doctest::toString(m_value) + " )"; } - -#ifdef DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING -String toString(char* in) { return toString(static_cast(in)); } -String toString(const char* in) { return String("\"") + (in ? in : "{null string}") + "\""; } -#endif // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING -String toString(bool in) { return in ? "true" : "false"; } -String toString(float in) { return detail::fpToString(in, 5) + "f"; } -String toString(double in) { return detail::fpToString(in, 10); } -String toString(double long in) { return detail::fpToString(in, 15); } - -String toString(char in) { - char buf[64]; - std::sprintf(buf, "%d", in); - return buf; +String toString(const Contains& in) { + return "Contains( " + in.string + " )"; } -String toString(char signed in) { - char buf[64]; - std::sprintf(buf, "%d", in); - return buf; +bool operator==(const String& lhs, const Contains& rhs) { return rhs.checkWith(lhs); } +bool operator==(const Contains& lhs, const String& rhs) { return lhs.checkWith(rhs); } +bool operator!=(const String& lhs, const Contains& rhs) { return !rhs.checkWith(lhs); } +bool operator!=(const Contains& lhs, const String& rhs) { return !lhs.checkWith(rhs); } + +namespace { + void color_to_stream(std::ostream&, Color::Enum) DOCTEST_BRANCH_ON_DISABLED({}, ;) +} // namespace + +namespace Color { + std::ostream& operator<<(std::ostream& s, Color::Enum code) { + color_to_stream(s, code); + return s; + } +} // namespace Color + +// clang-format off +const char* assertString(assertType::Enum at) { + DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4061) // enum 'x' in switch of enum 'y' is not explicitely handled + #define DOCTEST_GENERATE_ASSERT_TYPE_CASE(assert_type) case assertType::DT_ ## assert_type: return #assert_type + #define DOCTEST_GENERATE_ASSERT_TYPE_CASES(assert_type) \ + DOCTEST_GENERATE_ASSERT_TYPE_CASE(WARN_ ## assert_type); \ + DOCTEST_GENERATE_ASSERT_TYPE_CASE(CHECK_ ## assert_type); \ + DOCTEST_GENERATE_ASSERT_TYPE_CASE(REQUIRE_ ## assert_type) + switch(at) { + DOCTEST_GENERATE_ASSERT_TYPE_CASE(WARN); + DOCTEST_GENERATE_ASSERT_TYPE_CASE(CHECK); + DOCTEST_GENERATE_ASSERT_TYPE_CASE(REQUIRE); + + DOCTEST_GENERATE_ASSERT_TYPE_CASES(FALSE); + + DOCTEST_GENERATE_ASSERT_TYPE_CASES(THROWS); + + DOCTEST_GENERATE_ASSERT_TYPE_CASES(THROWS_AS); + + DOCTEST_GENERATE_ASSERT_TYPE_CASES(THROWS_WITH); + + DOCTEST_GENERATE_ASSERT_TYPE_CASES(THROWS_WITH_AS); + + DOCTEST_GENERATE_ASSERT_TYPE_CASES(NOTHROW); + + DOCTEST_GENERATE_ASSERT_TYPE_CASES(EQ); + DOCTEST_GENERATE_ASSERT_TYPE_CASES(NE); + DOCTEST_GENERATE_ASSERT_TYPE_CASES(GT); + DOCTEST_GENERATE_ASSERT_TYPE_CASES(LT); + DOCTEST_GENERATE_ASSERT_TYPE_CASES(GE); + DOCTEST_GENERATE_ASSERT_TYPE_CASES(LE); + + DOCTEST_GENERATE_ASSERT_TYPE_CASES(UNARY); + DOCTEST_GENERATE_ASSERT_TYPE_CASES(UNARY_FALSE); + + default: DOCTEST_INTERNAL_ERROR("Tried stringifying invalid assert type!"); + } + DOCTEST_MSVC_SUPPRESS_WARNING_POP } +// clang-format on -String toString(char unsigned in) { - char buf[64]; - std::sprintf(buf, "%ud", in); - return buf; +const char* failureString(assertType::Enum at) { + if(at & assertType::is_warn) //!OCLINT bitwise operator in conditional + return "WARNING"; + if(at & assertType::is_check) //!OCLINT bitwise operator in conditional + return "ERROR"; + if(at & assertType::is_require) //!OCLINT bitwise operator in conditional + return "FATAL ERROR"; + return ""; } -String toString(int short in) { - char buf[64]; - std::sprintf(buf, "%d", in); - return buf; +DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wnull-dereference") +DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH("-Wnull-dereference") +// depending on the current options this will remove the path of filenames +const char* skipPathFromFilename(const char* file) { +#ifndef DOCTEST_CONFIG_DISABLE + if(getContextOptions()->no_path_in_filenames) { + auto back = std::strrchr(file, '\\'); + auto forward = std::strrchr(file, '/'); + if(back || forward) { + if(back > forward) + forward = back; + return forward + 1; + } + } +#endif // DOCTEST_CONFIG_DISABLE + return file; } +DOCTEST_CLANG_SUPPRESS_WARNING_POP +DOCTEST_GCC_SUPPRESS_WARNING_POP -String toString(int short unsigned in) { - char buf[64]; - std::sprintf(buf, "%u", in); - return buf; +bool SubcaseSignature::operator==(const SubcaseSignature& other) const { + return m_line == other.m_line + && std::strcmp(m_file, other.m_file) == 0 + && m_name == other.m_name; } -String toString(int in) { - char buf[64]; - std::sprintf(buf, "%d", in); - return buf; +bool SubcaseSignature::operator<(const SubcaseSignature& other) const { + if(m_line != other.m_line) + return m_line < other.m_line; + if(std::strcmp(m_file, other.m_file) != 0) + return std::strcmp(m_file, other.m_file) < 0; + return m_name.compare(other.m_name) < 0; } -String toString(int unsigned in) { - char buf[64]; - std::sprintf(buf, "%u", in); - return buf; +DOCTEST_DEFINE_INTERFACE(IContextScope) + +namespace detail { + void filldata::fill(std::ostream* stream, const void* in) { + if (in) { *stream << in; } + else { *stream << "nullptr"; } + } + + template + String toStreamLit(T t) { + std::ostream* os = tlssPush(); + os->operator<<(t); + return tlssPop(); + } } -String toString(int long in) { - char buf[64]; - std::sprintf(buf, "%ld", in); - return buf; +#ifdef DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING +String toString(const char* in) { return String("\"") + (in ? in : "{null string}") + "\""; } +#endif // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING + +#if DOCTEST_MSVC >= DOCTEST_COMPILER(19, 20, 0) +// see this issue on why this is needed: https://github.com/doctest/doctest/issues/183 +String toString(const std::string& in) { return in.c_str(); } +#endif // VS 2019 + +String toString(String in) { return in; } + +String toString(std::nullptr_t) { return "nullptr"; } + +String toString(bool in) { return in ? "true" : "false"; } + +String toString(float in) { return toStreamLit(in); } +String toString(double in) { return toStreamLit(in); } +String toString(double long in) { return toStreamLit(in); } + +String toString(char in) { return toStreamLit(static_cast(in)); } +String toString(char signed in) { return toStreamLit(static_cast(in)); } +String toString(char unsigned in) { return toStreamLit(static_cast(in)); } +String toString(short in) { return toStreamLit(in); } +String toString(short unsigned in) { return toStreamLit(in); } +String toString(signed in) { return toStreamLit(in); } +String toString(unsigned in) { return toStreamLit(in); } +String toString(long in) { return toStreamLit(in); } +String toString(long unsigned in) { return toStreamLit(in); } +String toString(long long in) { return toStreamLit(in); } +String toString(long long unsigned in) { return toStreamLit(in); } + +Approx::Approx(double value) + : m_epsilon(static_cast(std::numeric_limits::epsilon()) * 100) + , m_scale(1.0) + , m_value(value) {} + +Approx Approx::operator()(double value) const { + Approx approx(value); + approx.epsilon(m_epsilon); + approx.scale(m_scale); + return approx; } -String toString(int long unsigned in) { - char buf[64]; - std::sprintf(buf, "%lu", in); - return buf; +Approx& Approx::epsilon(double newEpsilon) { + m_epsilon = newEpsilon; + return *this; +} +Approx& Approx::scale(double newScale) { + m_scale = newScale; + return *this; } -#ifdef DOCTEST_CONFIG_WITH_LONG_LONG -String toString(int long long in) { - char buf[64]; - std::sprintf(buf, "%lld", in); - return buf; +bool operator==(double lhs, const Approx& rhs) { + // Thanks to Richard Harris for his help refining this formula + return std::fabs(lhs - rhs.m_value) < + rhs.m_epsilon * (rhs.m_scale + std::max(std::fabs(lhs), std::fabs(rhs.m_value))); } -String toString(int long long unsigned in) { - char buf[64]; - std::sprintf(buf, "%llu", in); - return buf; +bool operator==(const Approx& lhs, double rhs) { return operator==(rhs, lhs); } +bool operator!=(double lhs, const Approx& rhs) { return !operator==(lhs, rhs); } +bool operator!=(const Approx& lhs, double rhs) { return !operator==(rhs, lhs); } +bool operator<=(double lhs, const Approx& rhs) { return lhs < rhs.m_value || lhs == rhs; } +bool operator<=(const Approx& lhs, double rhs) { return lhs.m_value < rhs || lhs == rhs; } +bool operator>=(double lhs, const Approx& rhs) { return lhs > rhs.m_value || lhs == rhs; } +bool operator>=(const Approx& lhs, double rhs) { return lhs.m_value > rhs || lhs == rhs; } +bool operator<(double lhs, const Approx& rhs) { return lhs < rhs.m_value && lhs != rhs; } +bool operator<(const Approx& lhs, double rhs) { return lhs.m_value < rhs && lhs != rhs; } +bool operator>(double lhs, const Approx& rhs) { return lhs > rhs.m_value && lhs != rhs; } +bool operator>(const Approx& lhs, double rhs) { return lhs.m_value > rhs && lhs != rhs; } + +String toString(const Approx& in) { + return "Approx( " + doctest::toString(in.m_value) + " )"; } -#endif // DOCTEST_CONFIG_WITH_LONG_LONG +const ContextOptions* getContextOptions() { return DOCTEST_BRANCH_ON_DISABLED(nullptr, g_cs); } -#ifdef DOCTEST_CONFIG_WITH_NULLPTR -String toString(std::nullptr_t) { return "nullptr"; } -#endif // DOCTEST_CONFIG_WITH_NULLPTR +DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4738) +template +IsNaN::operator bool() const { + return std::isnan(value) ^ flipped; +} +DOCTEST_MSVC_SUPPRESS_WARNING_POP +template struct DOCTEST_INTERFACE_DEF IsNaN; +template struct DOCTEST_INTERFACE_DEF IsNaN; +template struct DOCTEST_INTERFACE_DEF IsNaN; +template +String toString(IsNaN in) { return String(in.flipped ? "! " : "") + "IsNaN( " + doctest::toString(in.value) + " )"; } +String toString(IsNaN in) { return toString(in); } +String toString(IsNaN in) { return toString(in); } +String toString(IsNaN in) { return toString(in); } } // namespace doctest #ifdef DOCTEST_CONFIG_DISABLE -namespace doctest -{ -bool isRunningInTest() { return false; } +namespace doctest { Context::Context(int, const char* const*) {} -Context::~Context() {} +Context::~Context() = default; void Context::applyCommandLine(int, const char* const*) {} void Context::addFilter(const char*, const char*) {} void Context::clearFilters() {} +void Context::setOption(const char*, bool) {} void Context::setOption(const char*, int) {} void Context::setOption(const char*, const char*) {} bool Context::shouldExit() { return false; } +void Context::setAsDefaultForAssertsOutOfTestCases() {} +void Context::setAssertHandler(detail::assert_handler) {} +void Context::setCout(std::ostream*) {} int Context::run() { return 0; } + +int IReporter::get_num_active_contexts() { return 0; } +const IContextScope* const* IReporter::get_active_contexts() { return nullptr; } +int IReporter::get_num_stringified_contexts() { return 0; } +const String* IReporter::get_stringified_contexts() { return nullptr; } + +int registerReporter(const char*, int, IReporter*) { return 0; } + } // namespace doctest #else // DOCTEST_CONFIG_DISABLE @@ -3670,230 +4003,64 @@ int Context::run() { return 0; } #endif // DOCTEST_CONFIG_COLORS_WINDOWS && DOCTEST_CONFIG_COLORS_ANSI #endif // DOCTEST_CONFIG_COLORS_NONE -#if DOCTEST_MSVC || defined(__MINGW32__) -#if DOCTEST_MSVC >= DOCTEST_COMPILER(17, 0, 0) -#define DOCTEST_WINDOWS_SAL_IN_OPT _In_opt_ -#else // MSVC -#define DOCTEST_WINDOWS_SAL_IN_OPT -#endif // MSVC -extern "C" __declspec(dllimport) void __stdcall OutputDebugStringA( - DOCTEST_WINDOWS_SAL_IN_OPT const char*); -extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); -#endif // MSVC || __MINGW32__ - -#ifdef DOCTEST_CONFIG_COLORS_ANSI -#include -#endif // DOCTEST_CONFIG_COLORS_ANSI - -#ifdef DOCTEST_PLATFORM_WINDOWS - -// defines for a leaner windows.h -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN -#endif // WIN32_LEAN_AND_MEAN -#ifndef VC_EXTRA_LEAN -#define VC_EXTRA_LEAN -#endif // VC_EXTRA_LEAN -#ifndef NOMINMAX -#define NOMINMAX -#endif // NOMINMAX - -DOCTEST_MAKE_STD_HEADERS_CLEAN_FROM_WARNINGS_ON_WALL_BEGIN - -// not sure what AfxWin.h is for - here I do what Catch does -#ifdef __AFXDLL -#include -#else -#include -#endif -#include - -DOCTEST_MAKE_STD_HEADERS_CLEAN_FROM_WARNINGS_ON_WALL_END - -#else // DOCTEST_PLATFORM_WINDOWS - -#include - -#endif // DOCTEST_PLATFORM_WINDOWS - -namespace doctest_detail_test_suite_ns -{ +namespace doctest_detail_test_suite_ns { // holds the current test suite doctest::detail::TestSuite& getCurrentTestSuite() { - static doctest::detail::TestSuite data; + static doctest::detail::TestSuite data{}; return data; } } // namespace doctest_detail_test_suite_ns -namespace doctest -{ -namespace detail -{ - TestCase::TestCase(funcType test, const char* file, unsigned line, const TestSuite& test_suite, - const char* type, int template_id) - : m_test(test) - , m_name(0) - , m_type(type) - , m_test_suite(test_suite.m_test_suite) - , m_description(test_suite.m_description) - , m_skip(test_suite.m_skip) - , m_may_fail(test_suite.m_may_fail) - , m_should_fail(test_suite.m_should_fail) - , m_expected_failures(test_suite.m_expected_failures) - , m_timeout(test_suite.m_timeout) - , m_file(file) - , m_line(line) - , m_template_id(template_id) {} - - TestCase& TestCase::operator*(const char* in) { - m_name = in; - // make a new name with an appended type for templated test case - if(m_template_id != -1) { - m_full_name = String(m_name) + m_type; - // redirect the name to point to the newly constructed full name - m_name = m_full_name.c_str(); - } - return *this; - } - - TestCase& TestCase::operator=(const TestCase& other) { - m_test = other.m_test; - m_full_name = other.m_full_name; - m_name = other.m_name; - m_type = other.m_type; - m_test_suite = other.m_test_suite; - m_description = other.m_description; - m_skip = other.m_skip; - m_may_fail = other.m_may_fail; - m_should_fail = other.m_should_fail; - m_expected_failures = other.m_expected_failures; - m_timeout = other.m_timeout; - m_file = other.m_file; - m_line = other.m_line; - m_template_id = other.m_template_id; - - if(m_template_id != -1) - m_name = m_full_name.c_str(); - return *this; - } +namespace doctest { +namespace { + // the int (priority) is part of the key for automatic sorting - sadly one can register a + // reporter with a duplicate name and a different priority but hopefully that won't happen often :| + using reporterMap = std::map, reporterCreatorFunc>; - bool TestCase::operator<(const TestCase& other) const { - if(m_line != other.m_line) - return m_line < other.m_line; - const int file_cmp = std::strcmp(m_file, other.m_file); - if(file_cmp != 0) - return file_cmp < 0; - return m_template_id < other.m_template_id; + reporterMap& getReporters() { + static reporterMap data; + return data; } - - const char* assertString(assertType::Enum val) { - DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH( - 4062) // enumerator 'x' in switch of enum 'y' is not handled - switch(val) { //!OCLINT missing default in switch statements - // clang-format off - case assertType::DT_WARN : return "WARN"; - case assertType::DT_CHECK : return "CHECK"; - case assertType::DT_REQUIRE : return "REQUIRE"; - - case assertType::DT_WARN_FALSE : return "WARN_FALSE"; - case assertType::DT_CHECK_FALSE : return "CHECK_FALSE"; - case assertType::DT_REQUIRE_FALSE : return "REQUIRE_FALSE"; - - case assertType::DT_WARN_THROWS : return "WARN_THROWS"; - case assertType::DT_CHECK_THROWS : return "CHECK_THROWS"; - case assertType::DT_REQUIRE_THROWS : return "REQUIRE_THROWS"; - - case assertType::DT_WARN_THROWS_AS : return "WARN_THROWS_AS"; - case assertType::DT_CHECK_THROWS_AS : return "CHECK_THROWS_AS"; - case assertType::DT_REQUIRE_THROWS_AS : return "REQUIRE_THROWS_AS"; - - case assertType::DT_WARN_NOTHROW : return "WARN_NOTHROW"; - case assertType::DT_CHECK_NOTHROW : return "CHECK_NOTHROW"; - case assertType::DT_REQUIRE_NOTHROW : return "REQUIRE_NOTHROW"; - - case assertType::DT_WARN_EQ : return "WARN_EQ"; - case assertType::DT_CHECK_EQ : return "CHECK_EQ"; - case assertType::DT_REQUIRE_EQ : return "REQUIRE_EQ"; - case assertType::DT_WARN_NE : return "WARN_NE"; - case assertType::DT_CHECK_NE : return "CHECK_NE"; - case assertType::DT_REQUIRE_NE : return "REQUIRE_NE"; - case assertType::DT_WARN_GT : return "WARN_GT"; - case assertType::DT_CHECK_GT : return "CHECK_GT"; - case assertType::DT_REQUIRE_GT : return "REQUIRE_GT"; - case assertType::DT_WARN_LT : return "WARN_LT"; - case assertType::DT_CHECK_LT : return "CHECK_LT"; - case assertType::DT_REQUIRE_LT : return "REQUIRE_LT"; - case assertType::DT_WARN_GE : return "WARN_GE"; - case assertType::DT_CHECK_GE : return "CHECK_GE"; - case assertType::DT_REQUIRE_GE : return "REQUIRE_GE"; - case assertType::DT_WARN_LE : return "WARN_LE"; - case assertType::DT_CHECK_LE : return "CHECK_LE"; - case assertType::DT_REQUIRE_LE : return "REQUIRE_LE"; - - case assertType::DT_WARN_UNARY : return "WARN_UNARY"; - case assertType::DT_CHECK_UNARY : return "CHECK_UNARY"; - case assertType::DT_REQUIRE_UNARY : return "REQUIRE_UNARY"; - case assertType::DT_WARN_UNARY_FALSE : return "WARN_UNARY_FALSE"; - case assertType::DT_CHECK_UNARY_FALSE : return "CHECK_UNARY_FALSE"; - case assertType::DT_REQUIRE_UNARY_FALSE : return "REQUIRE_UNARY_FALSE"; - - case assertType::DT_FAST_WARN_EQ : return "FAST_WARN_EQ"; - case assertType::DT_FAST_CHECK_EQ : return "FAST_CHECK_EQ"; - case assertType::DT_FAST_REQUIRE_EQ : return "FAST_REQUIRE_EQ"; - case assertType::DT_FAST_WARN_NE : return "FAST_WARN_NE"; - case assertType::DT_FAST_CHECK_NE : return "FAST_CHECK_NE"; - case assertType::DT_FAST_REQUIRE_NE : return "FAST_REQUIRE_NE"; - case assertType::DT_FAST_WARN_GT : return "FAST_WARN_GT"; - case assertType::DT_FAST_CHECK_GT : return "FAST_CHECK_GT"; - case assertType::DT_FAST_REQUIRE_GT : return "FAST_REQUIRE_GT"; - case assertType::DT_FAST_WARN_LT : return "FAST_WARN_LT"; - case assertType::DT_FAST_CHECK_LT : return "FAST_CHECK_LT"; - case assertType::DT_FAST_REQUIRE_LT : return "FAST_REQUIRE_LT"; - case assertType::DT_FAST_WARN_GE : return "FAST_WARN_GE"; - case assertType::DT_FAST_CHECK_GE : return "FAST_CHECK_GE"; - case assertType::DT_FAST_REQUIRE_GE : return "FAST_REQUIRE_GE"; - case assertType::DT_FAST_WARN_LE : return "FAST_WARN_LE"; - case assertType::DT_FAST_CHECK_LE : return "FAST_CHECK_LE"; - case assertType::DT_FAST_REQUIRE_LE : return "FAST_REQUIRE_LE"; - - case assertType::DT_FAST_WARN_UNARY : return "FAST_WARN_UNARY"; - case assertType::DT_FAST_CHECK_UNARY : return "FAST_CHECK_UNARY"; - case assertType::DT_FAST_REQUIRE_UNARY : return "FAST_REQUIRE_UNARY"; - case assertType::DT_FAST_WARN_UNARY_FALSE : return "FAST_WARN_UNARY_FALSE"; - case assertType::DT_FAST_CHECK_UNARY_FALSE : return "FAST_CHECK_UNARY_FALSE"; - case assertType::DT_FAST_REQUIRE_UNARY_FALSE: return "FAST_REQUIRE_UNARY_FALSE"; - // clang-format on - } - DOCTEST_MSVC_SUPPRESS_WARNING_POP - return ""; + reporterMap& getListeners() { + static reporterMap data; + return data; } +} // namespace +namespace detail { +#define DOCTEST_ITERATE_THROUGH_REPORTERS(function, ...) \ + for(auto& curr_rep : g_cs->reporters_currently_used) \ + curr_rep->function(__VA_ARGS__) bool checkIfShouldThrow(assertType::Enum at) { if(at & assertType::is_require) //!OCLINT bitwise operator in conditional return true; if((at & assertType::is_check) //!OCLINT bitwise operator in conditional - && contextState->abort_after > 0 && - contextState->numFailedAssertions >= contextState->abort_after) + && getContextOptions()->abort_after > 0 && + (g_cs->numAssertsFailed + g_cs->numAssertsFailedCurrentTest_atomic) >= + getContextOptions()->abort_after) return true; return false; } - void throwException() { + #ifndef DOCTEST_CONFIG_NO_EXCEPTIONS - throw TestFailureException(); -#endif // DOCTEST_CONFIG_NO_EXCEPTIONS - } - void fastAssertThrowIfFlagSet(int flags) { - if(flags & assertAction::shouldthrow) //!OCLINT bitwise operator in conditional - throwException(); + DOCTEST_NORETURN void throwException() { + g_cs->shouldLogCurrentException = false; + throw TestFailureException(); // NOLINT(hicpp-exception-baseclass) } +#else // DOCTEST_CONFIG_NO_EXCEPTIONS + void throwException() {} +#endif // DOCTEST_CONFIG_NO_EXCEPTIONS +} // namespace detail +namespace { + using namespace detail; // matching of a string against a wildcard mask (case sensitivity configurable) taken from // https://www.codeproject.com/Articles/1088/Wildcard-string-compare-globbing int wildcmp(const char* str, const char* wild, bool caseSensitive) { - const char* cp = 0; - const char* mp = 0; + const char* cp = str; + const char* mp = wild; while((*str) && (*wild != '*')) { if((caseSensitive ? (*wild != *str) : (tolower(*wild) != tolower(*str))) && @@ -3927,187 +4094,209 @@ namespace detail return !*wild; } - //// C string hash function (djb2) - taken from http://www.cse.yorku.ca/~oz/hash.html - //unsigned hashStr(unsigned const char* str) { - // unsigned long hash = 5381; - // char c; - // while((c = *str++)) - // hash = ((hash << 5) + hash) + c; // hash * 33 + c - // return hash; - //} - // checks if the name matches any of the filters (and can be configured what to do when empty) - bool matchesAny(const char* name, const std::vector& filters, int matchEmpty, - bool caseSensitive) { - if(filters.empty() && matchEmpty) + bool matchesAny(const char* name, const std::vector& filters, bool matchEmpty, + bool caseSensitive) { + if (filters.empty() && matchEmpty) return true; - for(unsigned i = 0; i < filters.size(); ++i) - if(wildcmp(name, filters[i].c_str(), caseSensitive)) + for (auto& curr : filters) + if (wildcmp(name, curr.c_str(), caseSensitive)) return true; return false; } -#ifdef DOCTEST_PLATFORM_WINDOWS + unsigned long long hash(unsigned long long a, unsigned long long b) { + return (a << 5) + b; + } - typedef unsigned long long UInt64; + // C string hash function (djb2) - taken from http://www.cse.yorku.ca/~oz/hash.html + unsigned long long hash(const char* str) { + unsigned long long hash = 5381; + char c; + while ((c = *str++)) + hash = ((hash << 5) + hash) + c; // hash * 33 + c + return hash; + } - UInt64 getCurrentTicks() { - static UInt64 hz = 0, hzo = 0; - if(!hz) { - QueryPerformanceFrequency(reinterpret_cast(&hz)); - QueryPerformanceCounter(reinterpret_cast(&hzo)); - } - UInt64 t; - QueryPerformanceCounter(reinterpret_cast(&t)); - return ((t - hzo) * 1000000) / hz; + unsigned long long hash(const SubcaseSignature& sig) { + return hash(hash(hash(sig.m_file), hash(sig.m_name.c_str())), sig.m_line); } -#else // DOCTEST_PLATFORM_WINDOWS - typedef uint64_t UInt64; - - UInt64 getCurrentTicks() { - timeval t; - gettimeofday(&t, 0); - return static_cast(t.tv_sec) * 1000000 + static_cast(t.tv_usec); + unsigned long long hash(const std::vector& sigs, size_t count) { + unsigned long long running = 0; + auto end = sigs.begin() + count; + for (auto it = sigs.begin(); it != end; it++) { + running = hash(running, hash(*it)); + } + return running; } -#endif // DOCTEST_PLATFORM_WINDOWS - class Timer - { - public: - Timer() - : m_ticks(0) {} - void start() { m_ticks = getCurrentTicks(); } - unsigned int getElapsedMicroseconds() const { - return static_cast(getCurrentTicks() - m_ticks); - } - unsigned int getElapsedMilliseconds() const { - return static_cast(getElapsedMicroseconds() / 1000); + unsigned long long hash(const std::vector& sigs) { + unsigned long long running = 0; + for (const SubcaseSignature& sig : sigs) { + running = hash(running, hash(sig)); } - double getElapsedSeconds() const { return getElapsedMicroseconds() / 1000000.0; } - - private: - UInt64 m_ticks; - }; - - TestAccessibleContextState* getTestsContextState() { return contextState; } - - // TODO: remove this from here - void logTestEnd(); - - bool SubcaseSignature::operator<(const SubcaseSignature& other) const { - if(m_line != other.m_line) - return m_line < other.m_line; - if(std::strcmp(m_file, other.m_file) != 0) - return std::strcmp(m_file, other.m_file) < 0; - return std::strcmp(m_name, other.m_name) < 0; + return running; } - - Subcase::Subcase(const char* name, const char* file, int line) - : m_signature(name, file, line) - , m_entered(false) { - ContextState* s = contextState; - - // if we have already completed it - if(s->subcasesPassed.count(m_signature) != 0) - return; - - // check subcase filters - if(s->subcasesCurrentLevel < s->subcase_filter_levels) { - if(!matchesAny(m_signature.m_name, s->filters[6], 1, s->case_sensitive)) - return; - if(matchesAny(m_signature.m_name, s->filters[7], 0, s->case_sensitive)) - return; +} // namespace +namespace detail { + bool Subcase::checkFilters() { + if (g_cs->subcaseStack.size() < size_t(g_cs->subcase_filter_levels)) { + if (!matchesAny(m_signature.m_name.c_str(), g_cs->filters[6], true, g_cs->case_sensitive)) + return true; + if (matchesAny(m_signature.m_name.c_str(), g_cs->filters[7], false, g_cs->case_sensitive)) + return true; } + return false; + } - // if a Subcase on the same level has already been entered - if(s->subcasesEnteredLevels.count(s->subcasesCurrentLevel) != 0) { - s->subcasesHasSkipped = true; - return; + Subcase::Subcase(const String& name, const char* file, int line) + : m_signature({name, file, line}) { + if (!g_cs->reachedLeaf) { + if (g_cs->nextSubcaseStack.size() <= g_cs->subcaseStack.size() + || g_cs->nextSubcaseStack[g_cs->subcaseStack.size()] == m_signature) { + // Going down. + if (checkFilters()) { return; } + + g_cs->subcaseStack.push_back(m_signature); + g_cs->currentSubcaseDepth++; + m_entered = true; + DOCTEST_ITERATE_THROUGH_REPORTERS(subcase_start, m_signature); + } + } else { + if (g_cs->subcaseStack[g_cs->currentSubcaseDepth] == m_signature) { + // This subcase is reentered via control flow. + g_cs->currentSubcaseDepth++; + m_entered = true; + DOCTEST_ITERATE_THROUGH_REPORTERS(subcase_start, m_signature); + } else if (g_cs->nextSubcaseStack.size() <= g_cs->currentSubcaseDepth + && g_cs->fullyTraversedSubcases.find(hash(hash(g_cs->subcaseStack, g_cs->currentSubcaseDepth), hash(m_signature))) + == g_cs->fullyTraversedSubcases.end()) { + if (checkFilters()) { return; } + // This subcase is part of the one to be executed next. + g_cs->nextSubcaseStack.clear(); + g_cs->nextSubcaseStack.insert(g_cs->nextSubcaseStack.end(), + g_cs->subcaseStack.begin(), g_cs->subcaseStack.begin() + g_cs->currentSubcaseDepth); + g_cs->nextSubcaseStack.push_back(m_signature); + } } - - s->subcasesStack.push_back(*this); - if(s->hasLoggedCurrentTestStart) - logTestEnd(); - s->hasLoggedCurrentTestStart = false; - - s->subcasesEnteredLevels.insert(s->subcasesCurrentLevel++); - m_entered = true; } - Subcase::Subcase(const Subcase& other) - : m_signature(other.m_signature.m_name, other.m_signature.m_file, - other.m_signature.m_line) - , m_entered(other.m_entered) {} + DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4996) // std::uncaught_exception is deprecated in C++17 + DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH("-Wdeprecated-declarations") + DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wdeprecated-declarations") Subcase::~Subcase() { - if(m_entered) { - ContextState* s = contextState; + if (m_entered) { + g_cs->currentSubcaseDepth--; + + if (!g_cs->reachedLeaf) { + // Leaf. + g_cs->fullyTraversedSubcases.insert(hash(g_cs->subcaseStack)); + g_cs->nextSubcaseStack.clear(); + g_cs->reachedLeaf = true; + } else if (g_cs->nextSubcaseStack.empty()) { + // All children are finished. + g_cs->fullyTraversedSubcases.insert(hash(g_cs->subcaseStack)); + } - s->subcasesCurrentLevel--; - // only mark the subcase as passed if no subcases have been skipped - if(s->subcasesHasSkipped == false) - s->subcasesPassed.insert(m_signature); +#if defined(__cpp_lib_uncaught_exceptions) && __cpp_lib_uncaught_exceptions >= 201411L && (!defined(__MAC_OS_X_VERSION_MIN_REQUIRED) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 101200) + if(std::uncaught_exceptions() > 0 +#else + if(std::uncaught_exception() +#endif + && g_cs->shouldLogCurrentException) { + DOCTEST_ITERATE_THROUGH_REPORTERS( + test_case_exception, {"exception thrown in subcase - will translate later " + "when the whole test case has been exited (cannot " + "translate while there is an active exception)", + false}); + g_cs->shouldLogCurrentException = false; + } - if(!s->subcasesStack.empty()) - s->subcasesStack.pop_back(); - if(s->hasLoggedCurrentTestStart) - logTestEnd(); - s->hasLoggedCurrentTestStart = false; + DOCTEST_ITERATE_THROUGH_REPORTERS(subcase_end, DOCTEST_EMPTY); } } - Result::~Result() {} + DOCTEST_CLANG_SUPPRESS_WARNING_POP + DOCTEST_GCC_SUPPRESS_WARNING_POP + DOCTEST_MSVC_SUPPRESS_WARNING_POP + + Subcase::operator bool() const { return m_entered; } - Result& Result::operator=(const Result& other) { - m_passed = other.m_passed; - m_decomposition = other.m_decomposition; + Result::Result(bool passed, const String& decomposition) + : m_passed(passed) + , m_decomp(decomposition) {} + ExpressionDecomposer::ExpressionDecomposer(assertType::Enum at) + : m_at(at) {} + + TestSuite& TestSuite::operator*(const char* in) { + m_test_suite = in; return *this; } - // for sorting tests by file/line - int fileOrderComparator(const void* a, const void* b) { - const TestCase* lhs = *static_cast(a); - const TestCase* rhs = *static_cast(b); -#if DOCTEST_MSVC - // this is needed because MSVC gives different case for drive letters - // for __FILE__ when evaluated in a header and a source file - const int res = stricmp(lhs->m_file, rhs->m_file); -#else // MSVC - const int res = std::strcmp(lhs->m_file, rhs->m_file); -#endif // MSVC - if(res != 0) - return res; - return static_cast(lhs->m_line - rhs->m_line); + TestCase::TestCase(funcType test, const char* file, unsigned line, const TestSuite& test_suite, + const String& type, int template_id) { + m_file = file; + m_line = line; + m_name = nullptr; // will be later overridden in operator* + m_test_suite = test_suite.m_test_suite; + m_description = test_suite.m_description; + m_skip = test_suite.m_skip; + m_no_breaks = test_suite.m_no_breaks; + m_no_output = test_suite.m_no_output; + m_may_fail = test_suite.m_may_fail; + m_should_fail = test_suite.m_should_fail; + m_expected_failures = test_suite.m_expected_failures; + m_timeout = test_suite.m_timeout; + + m_test = test; + m_type = type; + m_template_id = template_id; } - // for sorting tests by suite/file/line - int suiteOrderComparator(const void* a, const void* b) { - const TestCase* lhs = *static_cast(a); - const TestCase* rhs = *static_cast(b); + TestCase::TestCase(const TestCase& other) + : TestCaseData() { + *this = other; + } - const int res = std::strcmp(lhs->m_test_suite, rhs->m_test_suite); - if(res != 0) - return res; - return fileOrderComparator(a, b); + DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(26434) // hides a non-virtual function + TestCase& TestCase::operator=(const TestCase& other) { + TestCaseData::operator=(other); + m_test = other.m_test; + m_type = other.m_type; + m_template_id = other.m_template_id; + m_full_name = other.m_full_name; + + if(m_template_id != -1) + m_name = m_full_name.c_str(); + return *this; } + DOCTEST_MSVC_SUPPRESS_WARNING_POP - // for sorting tests by name/suite/file/line - int nameOrderComparator(const void* a, const void* b) { - const TestCase* lhs = *static_cast(a); - const TestCase* rhs = *static_cast(b); - - const int res_name = std::strcmp(lhs->m_name, rhs->m_name); - if(res_name != 0) - return res_name; - return suiteOrderComparator(a, b); + TestCase& TestCase::operator*(const char* in) { + m_name = in; + // make a new name with an appended type for templated test case + if(m_template_id != -1) { + m_full_name = String(m_name) + "<" + m_type + ">"; + // redirect the name to point to the newly constructed full name + m_name = m_full_name.c_str(); + } + return *this; } - // sets the current test suite - int setTestSuite(const TestSuite& ts) { - doctest_detail_test_suite_ns::getCurrentTestSuite() = ts; - return 0; + bool TestCase::operator<(const TestCase& other) const { + // this will be used only to differentiate between test cases - not relevant for sorting + if(m_line != other.m_line) + return m_line < other.m_line; + const int name_cmp = strcmp(m_name, other.m_name); + if(name_cmp != 0) + return name_cmp < 0; + const int file_cmp = m_file.compare(other.m_file); + if(file_cmp != 0) + return file_cmp < 0; + return m_template_id < other.m_template_id; } // all the registered tests @@ -4115,72 +4304,48 @@ namespace detail static std::set data; return data; } - - // used by the macros for registering tests - int regTest(const TestCase& tc) { - getRegisteredTests().insert(tc); - return 0; +} // namespace detail +namespace { + using namespace detail; + // for sorting tests by file/line + bool fileOrderComparator(const TestCase* lhs, const TestCase* rhs) { + // this is needed because MSVC gives different case for drive letters + // for __FILE__ when evaluated in a header and a source file + const int res = lhs->m_file.compare(rhs->m_file, bool(DOCTEST_MSVC)); + if(res != 0) + return res < 0; + if(lhs->m_line != rhs->m_line) + return lhs->m_line < rhs->m_line; + return lhs->m_template_id < rhs->m_template_id; } - namespace Color - { - enum Code - { - None = 0, - White, - Red, - Green, - Blue, - Cyan, - Yellow, - Grey, - - Bright = 0x10, - - BrightRed = Bright | Red, - BrightGreen = Bright | Green, - LightGrey = Bright | Grey, - BrightWhite = Bright | White - }; - -#ifdef DOCTEST_CONFIG_COLORS_WINDOWS - HANDLE g_stdoutHandle; - WORD g_originalForegroundAttributes; - WORD g_originalBackgroundAttributes; - bool g_attrsInitted = false; -#endif // DOCTEST_CONFIG_COLORS_WINDOWS + // for sorting tests by suite/file/line + bool suiteOrderComparator(const TestCase* lhs, const TestCase* rhs) { + const int res = std::strcmp(lhs->m_test_suite, rhs->m_test_suite); + if(res != 0) + return res < 0; + return fileOrderComparator(lhs, rhs); + } - void init() { -#ifdef DOCTEST_CONFIG_COLORS_WINDOWS - if(!g_attrsInitted) { - g_stdoutHandle = GetStdHandle(STD_OUTPUT_HANDLE); - g_attrsInitted = true; - CONSOLE_SCREEN_BUFFER_INFO csbiInfo; - GetConsoleScreenBufferInfo(g_stdoutHandle, &csbiInfo); - g_originalForegroundAttributes = - csbiInfo.wAttributes & ~(BACKGROUND_GREEN | BACKGROUND_RED | - BACKGROUND_BLUE | BACKGROUND_INTENSITY); - g_originalBackgroundAttributes = - csbiInfo.wAttributes & ~(FOREGROUND_GREEN | FOREGROUND_RED | - FOREGROUND_BLUE | FOREGROUND_INTENSITY); - } -#endif // DOCTEST_CONFIG_COLORS_WINDOWS - } + // for sorting tests by name/suite/file/line + bool nameOrderComparator(const TestCase* lhs, const TestCase* rhs) { + const int res = std::strcmp(lhs->m_name, rhs->m_name); + if(res != 0) + return res < 0; + return suiteOrderComparator(lhs, rhs); + } - std::ostream& operator<<(std::ostream& s, Color::Code -#ifndef DOCTEST_CONFIG_COLORS_NONE - code -#endif // DOCTEST_CONFIG_COLORS_NONE - ) { - const ContextState* p = contextState; - if(p->no_colors) - return s; + DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wdeprecated-declarations") + void color_to_stream(std::ostream& s, Color::Enum code) { + static_cast(s); // for DOCTEST_CONFIG_COLORS_NONE or DOCTEST_CONFIG_COLORS_WINDOWS + static_cast(code); // for DOCTEST_CONFIG_COLORS_NONE #ifdef DOCTEST_CONFIG_COLORS_ANSI - if(isatty(STDOUT_FILENO) == false && p->force_colors == false) - return s; + if(g_no_colors || + (isatty(STDOUT_FILENO) == false && getContextOptions()->force_colors == false)) + return; - const char* col = ""; - // clang-format off + auto col = ""; + // clang-format off switch(code) { //!OCLINT missing break in switch statement / unnecessary default statement in covered switch statement case Color::Red: col = "[0;31m"; break; case Color::Green: col = "[0;32m"; break; @@ -4197,60 +4362,69 @@ namespace detail case Color::White: default: col = "[0m"; } - // clang-format on - s << "\033" << col; + // clang-format on + s << "\033" << col; #endif // DOCTEST_CONFIG_COLORS_ANSI #ifdef DOCTEST_CONFIG_COLORS_WINDOWS - if(isatty(fileno(stdout)) == false && p->force_colors == false) - return s; + if(g_no_colors || + (_isatty(_fileno(stdout)) == false && getContextOptions()->force_colors == false)) + return; -#define DOCTEST_SET_ATTR(x) \ - SetConsoleTextAttribute(g_stdoutHandle, x | g_originalBackgroundAttributes) + static struct ConsoleHelper { + HANDLE stdoutHandle; + WORD origFgAttrs; + WORD origBgAttrs; - // clang-format off - switch (code) { - case Color::White: DOCTEST_SET_ATTR(FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE); break; - case Color::Red: DOCTEST_SET_ATTR(FOREGROUND_RED); break; - case Color::Green: DOCTEST_SET_ATTR(FOREGROUND_GREEN); break; - case Color::Blue: DOCTEST_SET_ATTR(FOREGROUND_BLUE); break; - case Color::Cyan: DOCTEST_SET_ATTR(FOREGROUND_BLUE | FOREGROUND_GREEN); break; - case Color::Yellow: DOCTEST_SET_ATTR(FOREGROUND_RED | FOREGROUND_GREEN); break; - case Color::Grey: DOCTEST_SET_ATTR(0); break; - case Color::LightGrey: DOCTEST_SET_ATTR(FOREGROUND_INTENSITY); break; - case Color::BrightRed: DOCTEST_SET_ATTR(FOREGROUND_INTENSITY | FOREGROUND_RED); break; - case Color::BrightGreen: DOCTEST_SET_ATTR(FOREGROUND_INTENSITY | FOREGROUND_GREEN); break; - case Color::BrightWhite: DOCTEST_SET_ATTR(FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE); break; - case Color::None: - case Color::Bright: // invalid - default: DOCTEST_SET_ATTR(g_originalForegroundAttributes); + ConsoleHelper() { + stdoutHandle = GetStdHandle(STD_OUTPUT_HANDLE); + CONSOLE_SCREEN_BUFFER_INFO csbiInfo; + GetConsoleScreenBufferInfo(stdoutHandle, &csbiInfo); + origFgAttrs = csbiInfo.wAttributes & ~(BACKGROUND_GREEN | BACKGROUND_RED | + BACKGROUND_BLUE | BACKGROUND_INTENSITY); + origBgAttrs = csbiInfo.wAttributes & ~(FOREGROUND_GREEN | FOREGROUND_RED | + FOREGROUND_BLUE | FOREGROUND_INTENSITY); } - // clang-format on -#undef DOCTEST_SET_ATTR -#endif // DOCTEST_CONFIG_COLORS_WINDOWS - return s; + } ch; + +#define DOCTEST_SET_ATTR(x) SetConsoleTextAttribute(ch.stdoutHandle, x | ch.origBgAttrs) + + // clang-format off + switch (code) { + case Color::White: DOCTEST_SET_ATTR(FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE); break; + case Color::Red: DOCTEST_SET_ATTR(FOREGROUND_RED); break; + case Color::Green: DOCTEST_SET_ATTR(FOREGROUND_GREEN); break; + case Color::Blue: DOCTEST_SET_ATTR(FOREGROUND_BLUE); break; + case Color::Cyan: DOCTEST_SET_ATTR(FOREGROUND_BLUE | FOREGROUND_GREEN); break; + case Color::Yellow: DOCTEST_SET_ATTR(FOREGROUND_RED | FOREGROUND_GREEN); break; + case Color::Grey: DOCTEST_SET_ATTR(0); break; + case Color::LightGrey: DOCTEST_SET_ATTR(FOREGROUND_INTENSITY); break; + case Color::BrightRed: DOCTEST_SET_ATTR(FOREGROUND_INTENSITY | FOREGROUND_RED); break; + case Color::BrightGreen: DOCTEST_SET_ATTR(FOREGROUND_INTENSITY | FOREGROUND_GREEN); break; + case Color::BrightWhite: DOCTEST_SET_ATTR(FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE); break; + case Color::None: + case Color::Bright: // invalid + default: DOCTEST_SET_ATTR(ch.origFgAttrs); } - } // namespace Color + // clang-format on +#endif // DOCTEST_CONFIG_COLORS_WINDOWS + } + DOCTEST_CLANG_SUPPRESS_WARNING_POP std::vector& getExceptionTranslators() { static std::vector data; return data; } - void registerExceptionTranslatorImpl(const IExceptionTranslator* translateFunction) { - if(std::find(getExceptionTranslators().begin(), getExceptionTranslators().end(), - translateFunction) == getExceptionTranslators().end()) - getExceptionTranslators().push_back(translateFunction); - } - String translateActiveException() { #ifndef DOCTEST_CONFIG_NO_EXCEPTIONS - String res; - std::vector& translators = getExceptionTranslators(); - for(size_t i = 0; i < translators.size(); ++i) - if(translators[i]->translate(res)) + String res; + auto& translators = getExceptionTranslators(); + for(auto& curr : translators) + if(curr->translate(res)) return res; // clang-format off + DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH("-Wcatch-value") try { throw; } catch(std::exception& ex) { @@ -4262,59 +4436,138 @@ namespace detail } catch(...) { return "unknown exception"; } + DOCTEST_GCC_SUPPRESS_WARNING_POP // clang-format on #else // DOCTEST_CONFIG_NO_EXCEPTIONS return ""; #endif // DOCTEST_CONFIG_NO_EXCEPTIONS } +} // namespace - void writeStringToStream(std::ostream* s, const String& str) { *s << str; } +namespace detail { + // used by the macros for registering tests + int regTest(const TestCase& tc) { + getRegisteredTests().insert(tc); + return 0; + } + + // sets the current test suite + int setTestSuite(const TestSuite& ts) { + doctest_detail_test_suite_ns::getCurrentTestSuite() = ts; + return 0; + } + +#ifdef DOCTEST_IS_DEBUGGER_ACTIVE + bool isDebuggerActive() { return DOCTEST_IS_DEBUGGER_ACTIVE(); } +#else // DOCTEST_IS_DEBUGGER_ACTIVE +#ifdef DOCTEST_PLATFORM_LINUX + class ErrnoGuard { + public: + ErrnoGuard() : m_oldErrno(errno) {} + ~ErrnoGuard() { errno = m_oldErrno; } + private: + int m_oldErrno; + }; + // See the comments in Catch2 for the reasoning behind this implementation: + // https://github.com/catchorg/Catch2/blob/v2.13.1/include/internal/catch_debugger.cpp#L79-L102 + bool isDebuggerActive() { + ErrnoGuard guard; + std::ifstream in("/proc/self/status"); + for(std::string line; std::getline(in, line);) { + static const int PREFIX_LEN = 11; + if(line.compare(0, PREFIX_LEN, "TracerPid:\t") == 0) { + return line.length() > PREFIX_LEN && line[PREFIX_LEN] != '0'; + } + } + return false; + } +#elif defined(DOCTEST_PLATFORM_MAC) + // The following function is taken directly from the following technical note: + // https://developer.apple.com/library/archive/qa/qa1361/_index.html + // Returns true if the current process is being debugged (either + // running under the debugger or has a debugger attached post facto). + bool isDebuggerActive() { + int mib[4]; + kinfo_proc info; + size_t size; + // Initialize the flags so that, if sysctl fails for some bizarre + // reason, we get a predictable result. + info.kp_proc.p_flag = 0; + // Initialize mib, which tells sysctl the info we want, in this case + // we're looking for information about a specific process ID. + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PID; + mib[3] = getpid(); + // Call sysctl. + size = sizeof(info); + if(sysctl(mib, DOCTEST_COUNTOF(mib), &info, &size, 0, 0) != 0) { + std::cerr << "\nCall to sysctl failed - unable to determine if debugger is active **\n"; + return false; + } + // We're being debugged if the P_TRACED flag is set. + return ((info.kp_proc.p_flag & P_TRACED) != 0); + } +#elif DOCTEST_MSVC || defined(__MINGW32__) || defined(__MINGW64__) + bool isDebuggerActive() { return ::IsDebuggerPresent() != 0; } +#else + bool isDebuggerActive() { return false; } +#endif // Platform +#endif // DOCTEST_IS_DEBUGGER_ACTIVE + + void registerExceptionTranslatorImpl(const IExceptionTranslator* et) { + if(std::find(getExceptionTranslators().begin(), getExceptionTranslators().end(), et) == + getExceptionTranslators().end()) + getExceptionTranslators().push_back(et); + } + + DOCTEST_THREAD_LOCAL std::vector g_infoContexts; // for logging with INFO() + + ContextScopeBase::ContextScopeBase() { + g_infoContexts.push_back(this); + } + + ContextScopeBase::ContextScopeBase(ContextScopeBase&& other) noexcept { + if (other.need_to_destroy) { + other.destroy(); + } + other.need_to_destroy = false; + g_infoContexts.push_back(this); + } -#ifdef DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING - void toStream(std::ostream* s, char* in) { *s << in; } - void toStream(std::ostream* s, const char* in) { *s << in; } -#endif // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING - void toStream(std::ostream* s, bool in) { *s << std::boolalpha << in << std::noboolalpha; } - void toStream(std::ostream* s, float in) { *s << in; } - void toStream(std::ostream* s, double in) { *s << in; } - void toStream(std::ostream* s, double long in) { *s << in; } - - void toStream(std::ostream* s, char in) { *s << in; } - void toStream(std::ostream* s, char signed in) { *s << in; } - void toStream(std::ostream* s, char unsigned in) { *s << in; } - void toStream(std::ostream* s, int short in) { *s << in; } - void toStream(std::ostream* s, int short unsigned in) { *s << in; } - void toStream(std::ostream* s, int in) { *s << in; } - void toStream(std::ostream* s, int unsigned in) { *s << in; } - void toStream(std::ostream* s, int long in) { *s << in; } - void toStream(std::ostream* s, int long unsigned in) { *s << in; } - -#ifdef DOCTEST_CONFIG_WITH_LONG_LONG - void toStream(std::ostream* s, int long long in) { *s << in; } - void toStream(std::ostream* s, int long long unsigned in) { *s << in; } -#endif // DOCTEST_CONFIG_WITH_LONG_LONG - - void addToContexts(IContextScope* ptr) { contextState->contexts.push_back(ptr); } - void popFromContexts() { contextState->contexts.pop_back(); } DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4996) // std::uncaught_exception is deprecated in C++17 DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH("-Wdeprecated-declarations") - void useContextIfExceptionOccurred(IContextScope* ptr) { + DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wdeprecated-declarations") + + // destroy cannot be inlined into the destructor because that would mean calling stringify after + // ContextScope has been destroyed (base class destructors run after derived class destructors). + // Instead, ContextScope calls this method directly from its destructor. + void ContextScopeBase::destroy() { +#if defined(__cpp_lib_uncaught_exceptions) && __cpp_lib_uncaught_exceptions >= 201411L && (!defined(__MAC_OS_X_VERSION_MIN_REQUIRED) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 101200) + if(std::uncaught_exceptions() > 0) { +#else if(std::uncaught_exception()) { +#endif std::ostringstream s; - ptr->build(&s); - contextState->exceptionalContexts.push_back(s.str()); + this->stringify(&s); + g_cs->stringifiedContexts.push_back(s.str().c_str()); } + g_infoContexts.pop_back(); } + + DOCTEST_CLANG_SUPPRESS_WARNING_POP DOCTEST_GCC_SUPPRESS_WARNING_POP DOCTEST_MSVC_SUPPRESS_WARNING_POP - - void printSummary(std::ostream& s); +} // namespace detail +namespace { + using namespace detail; #if !defined(DOCTEST_CONFIG_POSIX_SIGNALS) && !defined(DOCTEST_CONFIG_WINDOWS_SEH) - void reportFatal(const std::string&) {} struct FatalConditionHandler { - void reset() {} + static void reset() {} + static void allocateAltStackMem() {} + static void freeAltStackMem() {} }; #else // DOCTEST_CONFIG_POSIX_SIGNALS || DOCTEST_CONFIG_WINDOWS_SEH @@ -4324,65 +4577,149 @@ namespace detail struct SignalDefs { - DWORD id; + DWORD id; const char* name; }; // There is no 1-1 mapping between signals and windows exceptions. // Windows can easily distinguish between SO and SigSegV, // but SigInt, SigTerm, etc are handled differently. SignalDefs signalDefs[] = { - {EXCEPTION_ILLEGAL_INSTRUCTION, "SIGILL - Illegal instruction signal"}, - {EXCEPTION_STACK_OVERFLOW, "SIGSEGV - Stack overflow"}, - {EXCEPTION_ACCESS_VIOLATION, "SIGSEGV - Segmentation violation signal"}, - {EXCEPTION_INT_DIVIDE_BY_ZERO, "Divide by zero error"}, + {static_cast(EXCEPTION_ILLEGAL_INSTRUCTION), + "SIGILL - Illegal instruction signal"}, + {static_cast(EXCEPTION_STACK_OVERFLOW), "SIGSEGV - Stack overflow"}, + {static_cast(EXCEPTION_ACCESS_VIOLATION), + "SIGSEGV - Segmentation violation signal"}, + {static_cast(EXCEPTION_INT_DIVIDE_BY_ZERO), "Divide by zero error"}, }; struct FatalConditionHandler { - static LONG CALLBACK handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo) { - for(size_t i = 0; i < DOCTEST_COUNTOF(signalDefs); ++i) { - if(ExceptionInfo->ExceptionRecord->ExceptionCode == signalDefs[i].id) { - reportFatal(signalDefs[i].name); + static LONG CALLBACK handleException(PEXCEPTION_POINTERS ExceptionInfo) { + // Multiple threads may enter this filter/handler at once. We want the error message to be printed on the + // console just once no matter how many threads have crashed. + DOCTEST_DECLARE_STATIC_MUTEX(mutex) + static bool execute = true; + { + DOCTEST_LOCK_MUTEX(mutex) + if(execute) { + bool reported = false; + for(size_t i = 0; i < DOCTEST_COUNTOF(signalDefs); ++i) { + if(ExceptionInfo->ExceptionRecord->ExceptionCode == signalDefs[i].id) { + reportFatal(signalDefs[i].name); + reported = true; + break; + } + } + if(reported == false) + reportFatal("Unhandled SEH exception caught"); + if(isDebuggerActive() && !g_cs->no_breaks) + DOCTEST_BREAK_INTO_DEBUGGER(); } + execute = false; } - // If its not an exception we care about, pass it along. - // This stops us from eating debugger breaks etc. - return EXCEPTION_CONTINUE_SEARCH; + std::exit(EXIT_FAILURE); } + static void allocateAltStackMem() {} + static void freeAltStackMem() {} + FatalConditionHandler() { isSet = true; // 32k seems enough for doctest to handle stack overflow, // but the value was found experimentally, so there is no strong guarantee - guaranteeSize = 32 * 1024; - exceptionHandlerHandle = 0; - // Register as first handler in current chain - exceptionHandlerHandle = AddVectoredExceptionHandler(1, handleVectoredException); + guaranteeSize = 32 * 1024; + // Register an unhandled exception filter + previousTop = SetUnhandledExceptionFilter(handleException); // Pass in guarantee size to be filled SetThreadStackGuarantee(&guaranteeSize); + + // On Windows uncaught exceptions from another thread, exceptions from + // destructors, or calls to std::terminate are not a SEH exception + + // The terminal handler gets called when: + // - std::terminate is called FROM THE TEST RUNNER THREAD + // - an exception is thrown from a destructor FROM THE TEST RUNNER THREAD + original_terminate_handler = std::get_terminate(); + std::set_terminate([]() DOCTEST_NOEXCEPT { + reportFatal("Terminate handler called"); + if(isDebuggerActive() && !g_cs->no_breaks) + DOCTEST_BREAK_INTO_DEBUGGER(); + std::exit(EXIT_FAILURE); // explicitly exit - otherwise the SIGABRT handler may be called as well + }); + + // SIGABRT is raised when: + // - std::terminate is called FROM A DIFFERENT THREAD + // - an exception is thrown from a destructor FROM A DIFFERENT THREAD + // - an uncaught exception is thrown FROM A DIFFERENT THREAD + prev_sigabrt_handler = std::signal(SIGABRT, [](int signal) DOCTEST_NOEXCEPT { + if(signal == SIGABRT) { + reportFatal("SIGABRT - Abort (abnormal termination) signal"); + if(isDebuggerActive() && !g_cs->no_breaks) + DOCTEST_BREAK_INTO_DEBUGGER(); + std::exit(EXIT_FAILURE); + } + }); + + // The following settings are taken from google test, and more + // specifically from UnitTest::Run() inside of gtest.cc + + // the user does not want to see pop-up dialogs about crashes + prev_error_mode_1 = SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOALIGNMENTFAULTEXCEPT | + SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX); + // This forces the abort message to go to stderr in all circumstances. + prev_error_mode_2 = _set_error_mode(_OUT_TO_STDERR); + // In the debug version, Visual Studio pops up a separate dialog + // offering a choice to debug the aborted program - we want to disable that. + prev_abort_behavior = _set_abort_behavior(0x0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT); + // In debug mode, the Windows CRT can crash with an assertion over invalid + // input (e.g. passing an invalid file descriptor). The default handling + // for these assertions is to pop up a dialog and wait for user input. + // Instead ask the CRT to dump such assertions to stderr non-interactively. + prev_report_mode = _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG); + prev_report_file = _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR); } static void reset() { if(isSet) { // Unregister handler and restore the old guarantee - RemoveVectoredExceptionHandler(exceptionHandlerHandle); + SetUnhandledExceptionFilter(previousTop); SetThreadStackGuarantee(&guaranteeSize); - exceptionHandlerHandle = 0; - isSet = false; + std::set_terminate(original_terminate_handler); + std::signal(SIGABRT, prev_sigabrt_handler); + SetErrorMode(prev_error_mode_1); + _set_error_mode(prev_error_mode_2); + _set_abort_behavior(prev_abort_behavior, _WRITE_ABORT_MSG | _CALL_REPORTFAULT); + static_cast(_CrtSetReportMode(_CRT_ASSERT, prev_report_mode)); + static_cast(_CrtSetReportFile(_CRT_ASSERT, prev_report_file)); + isSet = false; } } ~FatalConditionHandler() { reset(); } private: - static bool isSet; + static UINT prev_error_mode_1; + static int prev_error_mode_2; + static unsigned int prev_abort_behavior; + static int prev_report_mode; + static _HFILE prev_report_file; + static void (DOCTEST_CDECL *prev_sigabrt_handler)(int); + static std::terminate_handler original_terminate_handler; + static bool isSet; static ULONG guaranteeSize; - static PVOID exceptionHandlerHandle; + static LPTOP_LEVEL_EXCEPTION_FILTER previousTop; }; - bool FatalConditionHandler::isSet = false; - ULONG FatalConditionHandler::guaranteeSize = 0; - PVOID FatalConditionHandler::exceptionHandlerHandle = 0; + UINT FatalConditionHandler::prev_error_mode_1; + int FatalConditionHandler::prev_error_mode_2; + unsigned int FatalConditionHandler::prev_abort_behavior; + int FatalConditionHandler::prev_report_mode; + _HFILE FatalConditionHandler::prev_report_file; + void (DOCTEST_CDECL *FatalConditionHandler::prev_sigabrt_handler)(int); + std::terminate_handler FatalConditionHandler::original_terminate_handler; + bool FatalConditionHandler::isSet = false; + ULONG FatalConditionHandler::guaranteeSize = 0; + LPTOP_LEVEL_EXCEPTION_FILTER FatalConditionHandler::previousTop = nullptr; #else // DOCTEST_PLATFORM_WINDOWS @@ -4403,10 +4740,11 @@ namespace detail static bool isSet; static struct sigaction oldSigActions[DOCTEST_COUNTOF(signalDefs)]; static stack_t oldSigStack; - static char altStackMem[4 * SIGSTKSZ]; + static size_t altStackSize; + static char* altStackMem; static void handleSignal(int sig) { - std::string name = ""; + const char* name = ""; for(std::size_t i = 0; i < DOCTEST_COUNTOF(signalDefs); ++i) { SignalDefs& def = signalDefs[i]; if(sig == def.id) { @@ -4419,17 +4757,24 @@ namespace detail raise(sig); } + static void allocateAltStackMem() { + altStackMem = new char[altStackSize]; + } + + static void freeAltStackMem() { + delete[] altStackMem; + } + FatalConditionHandler() { isSet = true; stack_t sigStack; sigStack.ss_sp = altStackMem; - sigStack.ss_size = sizeof(altStackMem); + sigStack.ss_size = altStackSize; sigStack.ss_flags = 0; sigaltstack(&sigStack, &oldSigStack); - struct sigaction sa = {0}; - - sa.sa_handler = handleSignal; // NOLINT - sa.sa_flags = SA_ONSTACK; + struct sigaction sa = {}; + sa.sa_handler = handleSignal; + sa.sa_flags = SA_ONSTACK; for(std::size_t i = 0; i < DOCTEST_COUNTOF(signalDefs); ++i) { sigaction(signalDefs[i].id, &sa, &oldSigActions[i]); } @@ -4440,430 +4785,1621 @@ namespace detail if(isSet) { // Set signals back to previous values -- hopefully nobody overwrote them in the meantime for(std::size_t i = 0; i < DOCTEST_COUNTOF(signalDefs); ++i) { - sigaction(signalDefs[i].id, &oldSigActions[i], 0); + sigaction(signalDefs[i].id, &oldSigActions[i], nullptr); } // Return the old stack - sigaltstack(&oldSigStack, 0); + sigaltstack(&oldSigStack, nullptr); isSet = false; } } }; - bool FatalConditionHandler::isSet = false; + bool FatalConditionHandler::isSet = false; struct sigaction FatalConditionHandler::oldSigActions[DOCTEST_COUNTOF(signalDefs)] = {}; - stack_t FatalConditionHandler::oldSigStack = {}; - char FatalConditionHandler::altStackMem[] = {}; + stack_t FatalConditionHandler::oldSigStack = {}; + size_t FatalConditionHandler::altStackSize = 4 * SIGSTKSZ; + char* FatalConditionHandler::altStackMem = nullptr; #endif // DOCTEST_PLATFORM_WINDOWS #endif // DOCTEST_CONFIG_POSIX_SIGNALS || DOCTEST_CONFIG_WINDOWS_SEH - void separator_to_stream(std::ostream& s) { - s << Color::Yellow - << "===============================================================================\n"; +} // namespace + +namespace { + using namespace detail; + +#ifdef DOCTEST_PLATFORM_WINDOWS +#define DOCTEST_OUTPUT_DEBUG_STRING(text) ::OutputDebugStringA(text) +#else + // TODO: integration with XCode and other IDEs +#define DOCTEST_OUTPUT_DEBUG_STRING(text) +#endif // Platform + + void addAssert(assertType::Enum at) { + if((at & assertType::is_warn) == 0) //!OCLINT bitwise operator in conditional + g_cs->numAssertsCurrentTest_atomic++; } - // depending on the current options this will remove the path of filenames - const char* fileForOutput(const char* file) { - if(contextState->no_path_in_filenames) { - const char* back = std::strrchr(file, '\\'); - const char* forward = std::strrchr(file, '/'); - if(back || forward) { - if(back > forward) - forward = back; - return forward + 1; - } + void addFailedAssert(assertType::Enum at) { + if((at & assertType::is_warn) == 0) //!OCLINT bitwise operator in conditional + g_cs->numAssertsFailedCurrentTest_atomic++; + } + +#if defined(DOCTEST_CONFIG_POSIX_SIGNALS) || defined(DOCTEST_CONFIG_WINDOWS_SEH) + void reportFatal(const std::string& message) { + g_cs->failure_flags |= TestCaseFailureReason::Crash; + + DOCTEST_ITERATE_THROUGH_REPORTERS(test_case_exception, {message.c_str(), true}); + + while (g_cs->subcaseStack.size()) { + g_cs->subcaseStack.pop_back(); + DOCTEST_ITERATE_THROUGH_REPORTERS(subcase_end, DOCTEST_EMPTY); } - return file; + + g_cs->finalizeTestCaseData(); + + DOCTEST_ITERATE_THROUGH_REPORTERS(test_case_end, *g_cs); + + DOCTEST_ITERATE_THROUGH_REPORTERS(test_run_end, *g_cs); } +#endif // DOCTEST_CONFIG_POSIX_SIGNALS || DOCTEST_CONFIG_WINDOWS_SEH +} // namespace + +AssertData::AssertData(assertType::Enum at, const char* file, int line, const char* expr, + const char* exception_type, const StringContains& exception_string) + : m_test_case(g_cs->currentTest), m_at(at), m_file(file), m_line(line), m_expr(expr), + m_failed(true), m_threw(false), m_threw_as(false), m_exception_type(exception_type), + m_exception_string(exception_string) { +#if DOCTEST_MSVC + if (m_expr[0] == ' ') // this happens when variadic macros are disabled under MSVC + ++m_expr; +#endif // MSVC +} + +namespace detail { + ResultBuilder::ResultBuilder(assertType::Enum at, const char* file, int line, const char* expr, + const char* exception_type, const String& exception_string) + : AssertData(at, file, line, expr, exception_type, exception_string) { } + + ResultBuilder::ResultBuilder(assertType::Enum at, const char* file, int line, const char* expr, + const char* exception_type, const Contains& exception_string) + : AssertData(at, file, line, expr, exception_type, exception_string) { } - void file_line_to_stream(std::ostream& s, const char* file, int line, const char* tail = "") { - s << Color::LightGrey << fileForOutput(file) << (contextState->gnu_file_line ? ":" : "(") - << (contextState->no_line_numbers ? 0 : line) // 0 or the real num depending on the option - << (contextState->gnu_file_line ? ":" : "):") << tail; + void ResultBuilder::setResult(const Result& res) { + m_decomp = res.m_decomp; + m_failed = !res.m_passed; } - const char* getSuccessOrFailString(bool success, assertType::Enum at, const char* success_str) { - if(success) - return success_str; - if(at & assertType::is_warn) //!OCLINT bitwise operator in conditional - return "WARNING: "; - if(at & assertType::is_check) //!OCLINT bitwise operator in conditional - return "ERROR: "; - if(at & assertType::is_require) //!OCLINT bitwise operator in conditional - return "FATAL ERROR: "; - return ""; + void ResultBuilder::translateException() { + m_threw = true; + m_exception = translateActiveException(); } - Color::Code getSuccessOrFailColor(bool success, assertType::Enum at) { - return success ? Color::BrightGreen : - (at & assertType::is_warn) ? Color::Yellow : Color::Red; + bool ResultBuilder::log() { + if(m_at & assertType::is_throws) { //!OCLINT bitwise operator in conditional + m_failed = !m_threw; + } else if((m_at & assertType::is_throws_as) && (m_at & assertType::is_throws_with)) { //!OCLINT + m_failed = !m_threw_as || !m_exception_string.check(m_exception); + } else if(m_at & assertType::is_throws_as) { //!OCLINT bitwise operator in conditional + m_failed = !m_threw_as; + } else if(m_at & assertType::is_throws_with) { //!OCLINT bitwise operator in conditional + m_failed = !m_exception_string.check(m_exception); + } else if(m_at & assertType::is_nothrow) { //!OCLINT bitwise operator in conditional + m_failed = m_threw; + } + + if(m_exception.size()) + m_exception = "\"" + m_exception + "\""; + + if(is_running_in_test) { + addAssert(m_at); + DOCTEST_ITERATE_THROUGH_REPORTERS(log_assert, *this); + + if(m_failed) + addFailedAssert(m_at); + } else if(m_failed) { + failed_out_of_a_testing_context(*this); + } + + return m_failed && isDebuggerActive() && !getContextOptions()->no_breaks && + (g_cs->currentTest == nullptr || !g_cs->currentTest->m_no_breaks); // break into debugger } - void successOrFailColoredStringToStream(std::ostream& s, bool success, assertType::Enum at, - const char* success_str = "SUCCESS: ") { - s << getSuccessOrFailColor(success, at) << getSuccessOrFailString(success, at, success_str); + void ResultBuilder::react() const { + if(m_failed && checkIfShouldThrow(m_at)) + throwException(); } -#ifdef DOCTEST_PLATFORM_MAC -#include -#include -#include - // The following function is taken directly from the following technical note: - // http://developer.apple.com/library/mac/#qa/qa2004/qa1361.html - // Returns true if the current process is being debugged (either - // running under the debugger or has a debugger attached post facto). - bool isDebuggerActive() { - int mib[4]; - kinfo_proc info; - size_t size; - // Initialize the flags so that, if sysctl fails for some bizarre - // reason, we get a predictable result. - info.kp_proc.p_flag = 0; - // Initialize mib, which tells sysctl the info we want, in this case - // we're looking for information about a specific process ID. - mib[0] = CTL_KERN; - mib[1] = KERN_PROC; - mib[2] = KERN_PROC_PID; - mib[3] = getpid(); - // Call sysctl. - size = sizeof(info); - if(sysctl(mib, DOCTEST_COUNTOF(mib), &info, &size, 0, 0) != 0) { - fprintf(stderr, "\n** Call to sysctl failed - unable to determine if debugger is " - "active **\n\n"); - return false; + void failed_out_of_a_testing_context(const AssertData& ad) { + if(g_cs->ah) + g_cs->ah(ad); + else + std::abort(); + } + + bool decomp_assert(assertType::Enum at, const char* file, int line, const char* expr, + const Result& result) { + bool failed = !result.m_passed; + + // ################################################################################### + // IF THE DEBUGGER BREAKS HERE - GO 1 LEVEL UP IN THE CALLSTACK FOR THE FAILING ASSERT + // THIS IS THE EFFECT OF HAVING 'DOCTEST_CONFIG_SUPER_FAST_ASSERTS' DEFINED + // ################################################################################### + DOCTEST_ASSERT_OUT_OF_TESTS(result.m_decomp); + DOCTEST_ASSERT_IN_TESTS(result.m_decomp); + return !failed; + } + + MessageBuilder::MessageBuilder(const char* file, int line, assertType::Enum severity) { + m_stream = tlssPush(); + m_file = file; + m_line = line; + m_severity = severity; + } + + MessageBuilder::~MessageBuilder() { + if (!logged) + tlssPop(); + } + + DOCTEST_DEFINE_INTERFACE(IExceptionTranslator) + + bool MessageBuilder::log() { + if (!logged) { + m_string = tlssPop(); + logged = true; } - // We're being debugged if the P_TRACED flag is set. - return ((info.kp_proc.p_flag & P_TRACED) != 0); + + DOCTEST_ITERATE_THROUGH_REPORTERS(log_message, *this); + + const bool isWarn = m_severity & assertType::is_warn; + + // warn is just a message in this context so we don't treat it as an assert + if(!isWarn) { + addAssert(m_severity); + addFailedAssert(m_severity); + } + + return isDebuggerActive() && !getContextOptions()->no_breaks && !isWarn && + (g_cs->currentTest == nullptr || !g_cs->currentTest->m_no_breaks); // break into debugger + } + + void MessageBuilder::react() { + if(m_severity & assertType::is_require) //!OCLINT bitwise operator in conditional + throwException(); + } +} // namespace detail +namespace { + using namespace detail; + + // clang-format off + +// ================================================================================================= +// The following code has been taken verbatim from Catch2/include/internal/catch_xmlwriter.h/cpp +// This is done so cherry-picking bug fixes is trivial - even the style/formatting is untouched. +// ================================================================================================= + + class XmlEncode { + public: + enum ForWhat { ForTextNodes, ForAttributes }; + + XmlEncode( std::string const& str, ForWhat forWhat = ForTextNodes ); + + void encodeTo( std::ostream& os ) const; + + friend std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ); + + private: + std::string m_str; + ForWhat m_forWhat; + }; + + class XmlWriter { + public: + + class ScopedElement { + public: + ScopedElement( XmlWriter* writer ); + + ScopedElement( ScopedElement&& other ) DOCTEST_NOEXCEPT; + ScopedElement& operator=( ScopedElement&& other ) DOCTEST_NOEXCEPT; + + ~ScopedElement(); + + ScopedElement& writeText( std::string const& text, bool indent = true ); + + template + ScopedElement& writeAttribute( std::string const& name, T const& attribute ) { + m_writer->writeAttribute( name, attribute ); + return *this; + } + + private: + mutable XmlWriter* m_writer = nullptr; + }; + + XmlWriter( std::ostream& os = std::cout ); + ~XmlWriter(); + + XmlWriter( XmlWriter const& ) = delete; + XmlWriter& operator=( XmlWriter const& ) = delete; + + XmlWriter& startElement( std::string const& name ); + + ScopedElement scopedElement( std::string const& name ); + + XmlWriter& endElement(); + + XmlWriter& writeAttribute( std::string const& name, std::string const& attribute ); + + XmlWriter& writeAttribute( std::string const& name, const char* attribute ); + + XmlWriter& writeAttribute( std::string const& name, bool attribute ); + + template + XmlWriter& writeAttribute( std::string const& name, T const& attribute ) { + std::stringstream rss; + rss << attribute; + return writeAttribute( name, rss.str() ); + } + + XmlWriter& writeText( std::string const& text, bool indent = true ); + + //XmlWriter& writeComment( std::string const& text ); + + //void writeStylesheetRef( std::string const& url ); + + //XmlWriter& writeBlankLine(); + + void ensureTagClosed(); + + void writeDeclaration(); + + private: + + void newlineIfNecessary(); + + bool m_tagIsOpen = false; + bool m_needsNewline = false; + std::vector m_tags; + std::string m_indent; + std::ostream& m_os; + }; + +// ================================================================================================= +// The following code has been taken verbatim from Catch2/include/internal/catch_xmlwriter.h/cpp +// This is done so cherry-picking bug fixes is trivial - even the style/formatting is untouched. +// ================================================================================================= + +using uchar = unsigned char; + +namespace { + + size_t trailingBytes(unsigned char c) { + if ((c & 0xE0) == 0xC0) { + return 2; + } + if ((c & 0xF0) == 0xE0) { + return 3; + } + if ((c & 0xF8) == 0xF0) { + return 4; + } + DOCTEST_INTERNAL_ERROR("Invalid multibyte utf-8 start byte encountered"); + } + + uint32_t headerValue(unsigned char c) { + if ((c & 0xE0) == 0xC0) { + return c & 0x1F; + } + if ((c & 0xF0) == 0xE0) { + return c & 0x0F; + } + if ((c & 0xF8) == 0xF0) { + return c & 0x07; + } + DOCTEST_INTERNAL_ERROR("Invalid multibyte utf-8 start byte encountered"); + } + + void hexEscapeChar(std::ostream& os, unsigned char c) { + std::ios_base::fmtflags f(os.flags()); + os << "\\x" + << std::uppercase << std::hex << std::setfill('0') << std::setw(2) + << static_cast(c); + os.flags(f); + } + +} // anonymous namespace + + XmlEncode::XmlEncode( std::string const& str, ForWhat forWhat ) + : m_str( str ), + m_forWhat( forWhat ) + {} + + void XmlEncode::encodeTo( std::ostream& os ) const { + // Apostrophe escaping not necessary if we always use " to write attributes + // (see: https://www.w3.org/TR/xml/#syntax) + + for( std::size_t idx = 0; idx < m_str.size(); ++ idx ) { + uchar c = m_str[idx]; + switch (c) { + case '<': os << "<"; break; + case '&': os << "&"; break; + + case '>': + // See: https://www.w3.org/TR/xml/#syntax + if (idx > 2 && m_str[idx - 1] == ']' && m_str[idx - 2] == ']') + os << ">"; + else + os << c; + break; + + case '\"': + if (m_forWhat == ForAttributes) + os << """; + else + os << c; + break; + + default: + // Check for control characters and invalid utf-8 + + // Escape control characters in standard ascii + // see https://stackoverflow.com/questions/404107/why-are-control-characters-illegal-in-xml-1-0 + if (c < 0x09 || (c > 0x0D && c < 0x20) || c == 0x7F) { + hexEscapeChar(os, c); + break; + } + + // Plain ASCII: Write it to stream + if (c < 0x7F) { + os << c; + break; + } + + // UTF-8 territory + // Check if the encoding is valid and if it is not, hex escape bytes. + // Important: We do not check the exact decoded values for validity, only the encoding format + // First check that this bytes is a valid lead byte: + // This means that it is not encoded as 1111 1XXX + // Or as 10XX XXXX + if (c < 0xC0 || + c >= 0xF8) { + hexEscapeChar(os, c); + break; + } + + auto encBytes = trailingBytes(c); + // Are there enough bytes left to avoid accessing out-of-bounds memory? + if (idx + encBytes - 1 >= m_str.size()) { + hexEscapeChar(os, c); + break; + } + // The header is valid, check data + // The next encBytes bytes must together be a valid utf-8 + // This means: bitpattern 10XX XXXX and the extracted value is sane (ish) + bool valid = true; + uint32_t value = headerValue(c); + for (std::size_t n = 1; n < encBytes; ++n) { + uchar nc = m_str[idx + n]; + valid &= ((nc & 0xC0) == 0x80); + value = (value << 6) | (nc & 0x3F); + } + + if ( + // Wrong bit pattern of following bytes + (!valid) || + // Overlong encodings + (value < 0x80) || + ( value < 0x800 && encBytes > 2) || // removed "0x80 <= value &&" because redundant + (0x800 < value && value < 0x10000 && encBytes > 3) || + // Encoded value out of range + (value >= 0x110000) + ) { + hexEscapeChar(os, c); + break; + } + + // If we got here, this is in fact a valid(ish) utf-8 sequence + for (std::size_t n = 0; n < encBytes; ++n) { + os << m_str[idx + n]; + } + idx += encBytes - 1; + break; + } + } + } + + std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ) { + xmlEncode.encodeTo( os ); + return os; + } + + XmlWriter::ScopedElement::ScopedElement( XmlWriter* writer ) + : m_writer( writer ) + {} + + XmlWriter::ScopedElement::ScopedElement( ScopedElement&& other ) DOCTEST_NOEXCEPT + : m_writer( other.m_writer ){ + other.m_writer = nullptr; + } + XmlWriter::ScopedElement& XmlWriter::ScopedElement::operator=( ScopedElement&& other ) DOCTEST_NOEXCEPT { + if ( m_writer ) { + m_writer->endElement(); + } + m_writer = other.m_writer; + other.m_writer = nullptr; + return *this; + } + + + XmlWriter::ScopedElement::~ScopedElement() { + if( m_writer ) + m_writer->endElement(); + } + + XmlWriter::ScopedElement& XmlWriter::ScopedElement::writeText( std::string const& text, bool indent ) { + m_writer->writeText( text, indent ); + return *this; + } + + XmlWriter::XmlWriter( std::ostream& os ) : m_os( os ) + { + // writeDeclaration(); // called explicitly by the reporters that use the writer class - see issue #627 + } + + XmlWriter::~XmlWriter() { + while( !m_tags.empty() ) + endElement(); + } + + XmlWriter& XmlWriter::startElement( std::string const& name ) { + ensureTagClosed(); + newlineIfNecessary(); + m_os << m_indent << '<' << name; + m_tags.push_back( name ); + m_indent += " "; + m_tagIsOpen = true; + return *this; + } + + XmlWriter::ScopedElement XmlWriter::scopedElement( std::string const& name ) { + ScopedElement scoped( this ); + startElement( name ); + return scoped; + } + + XmlWriter& XmlWriter::endElement() { + newlineIfNecessary(); + m_indent = m_indent.substr( 0, m_indent.size()-2 ); + if( m_tagIsOpen ) { + m_os << "/>"; + m_tagIsOpen = false; + } + else { + m_os << m_indent << ""; + } + m_os << std::endl; + m_tags.pop_back(); + return *this; } -#elif DOCTEST_MSVC || defined(__MINGW32__) - bool isDebuggerActive() { return ::IsDebuggerPresent() != 0; } -#else - bool isDebuggerActive() { return false; } -#endif // Platform + XmlWriter& XmlWriter::writeAttribute( std::string const& name, std::string const& attribute ) { + if( !name.empty() && !attribute.empty() ) + m_os << ' ' << name << "=\"" << XmlEncode( attribute, XmlEncode::ForAttributes ) << '"'; + return *this; + } + + XmlWriter& XmlWriter::writeAttribute( std::string const& name, const char* attribute ) { + if( !name.empty() && attribute && attribute[0] != '\0' ) + m_os << ' ' << name << "=\"" << XmlEncode( attribute, XmlEncode::ForAttributes ) << '"'; + return *this; + } + + XmlWriter& XmlWriter::writeAttribute( std::string const& name, bool attribute ) { + m_os << ' ' << name << "=\"" << ( attribute ? "true" : "false" ) << '"'; + return *this; + } + + XmlWriter& XmlWriter::writeText( std::string const& text, bool indent ) { + if( !text.empty() ){ + bool tagWasOpen = m_tagIsOpen; + ensureTagClosed(); + if( tagWasOpen && indent ) + m_os << m_indent; + m_os << XmlEncode( text ); + m_needsNewline = true; + } + return *this; + } + + //XmlWriter& XmlWriter::writeComment( std::string const& text ) { + // ensureTagClosed(); + // m_os << m_indent << ""; + // m_needsNewline = true; + // return *this; + //} + + //void XmlWriter::writeStylesheetRef( std::string const& url ) { + // m_os << "\n"; + //} + + //XmlWriter& XmlWriter::writeBlankLine() { + // ensureTagClosed(); + // m_os << '\n'; + // return *this; + //} + + void XmlWriter::ensureTagClosed() { + if( m_tagIsOpen ) { + m_os << ">" << std::endl; + m_tagIsOpen = false; + } + } + + void XmlWriter::writeDeclaration() { + m_os << "\n"; + } + + void XmlWriter::newlineIfNecessary() { + if( m_needsNewline ) { + m_os << std::endl; + m_needsNewline = false; + } + } + +// ================================================================================================= +// End of copy-pasted code from Catch +// ================================================================================================= + + // clang-format on + + struct XmlReporter : public IReporter + { + XmlWriter xml; + DOCTEST_DECLARE_MUTEX(mutex) + + // caching pointers/references to objects of these types - safe to do + const ContextOptions& opt; + const TestCaseData* tc = nullptr; + + XmlReporter(const ContextOptions& co) + : xml(*co.cout) + , opt(co) {} + + void log_contexts() { + int num_contexts = get_num_active_contexts(); + if(num_contexts) { + auto contexts = get_active_contexts(); + std::stringstream ss; + for(int i = 0; i < num_contexts; ++i) { + contexts[i]->stringify(&ss); + xml.scopedElement("Info").writeText(ss.str()); + ss.str(""); + } + } + } + + unsigned line(unsigned l) const { return opt.no_line_numbers ? 0 : l; } + + void test_case_start_impl(const TestCaseData& in) { + bool open_ts_tag = false; + if(tc != nullptr) { // we have already opened a test suite + if(std::strcmp(tc->m_test_suite, in.m_test_suite) != 0) { + xml.endElement(); + open_ts_tag = true; + } + } + else { + open_ts_tag = true; // first test case ==> first test suite + } + + if(open_ts_tag) { + xml.startElement("TestSuite"); + xml.writeAttribute("name", in.m_test_suite); + } + + tc = ∈ + xml.startElement("TestCase") + .writeAttribute("name", in.m_name) + .writeAttribute("filename", skipPathFromFilename(in.m_file.c_str())) + .writeAttribute("line", line(in.m_line)) + .writeAttribute("description", in.m_description); + + if(Approx(in.m_timeout) != 0) + xml.writeAttribute("timeout", in.m_timeout); + if(in.m_may_fail) + xml.writeAttribute("may_fail", true); + if(in.m_should_fail) + xml.writeAttribute("should_fail", true); + } + + // ========================================================================================= + // WHAT FOLLOWS ARE OVERRIDES OF THE VIRTUAL METHODS OF THE REPORTER INTERFACE + // ========================================================================================= + + void report_query(const QueryData& in) override { + test_run_start(); + if(opt.list_reporters) { + for(auto& curr : getListeners()) + xml.scopedElement("Listener") + .writeAttribute("priority", curr.first.first) + .writeAttribute("name", curr.first.second); + for(auto& curr : getReporters()) + xml.scopedElement("Reporter") + .writeAttribute("priority", curr.first.first) + .writeAttribute("name", curr.first.second); + } else if(opt.count || opt.list_test_cases) { + for(unsigned i = 0; i < in.num_data; ++i) { + xml.scopedElement("TestCase").writeAttribute("name", in.data[i]->m_name) + .writeAttribute("testsuite", in.data[i]->m_test_suite) + .writeAttribute("filename", skipPathFromFilename(in.data[i]->m_file.c_str())) + .writeAttribute("line", line(in.data[i]->m_line)) + .writeAttribute("skipped", in.data[i]->m_skip); + } + xml.scopedElement("OverallResultsTestCases") + .writeAttribute("unskipped", in.run_stats->numTestCasesPassingFilters); + } else if(opt.list_test_suites) { + for(unsigned i = 0; i < in.num_data; ++i) + xml.scopedElement("TestSuite").writeAttribute("name", in.data[i]->m_test_suite); + xml.scopedElement("OverallResultsTestCases") + .writeAttribute("unskipped", in.run_stats->numTestCasesPassingFilters); + xml.scopedElement("OverallResultsTestSuites") + .writeAttribute("unskipped", in.run_stats->numTestSuitesPassingFilters); + } + xml.endElement(); + } + + void test_run_start() override { + xml.writeDeclaration(); + + // remove .exe extension - mainly to have the same output on UNIX and Windows + std::string binary_name = skipPathFromFilename(opt.binary_name.c_str()); #ifdef DOCTEST_PLATFORM_WINDOWS - void myOutputDebugString(const String& text) { ::OutputDebugStringA(text.c_str()); } -#else - // TODO: integration with XCode and other IDEs - void myOutputDebugString(const String&) {} -#endif // Platform + if(binary_name.rfind(".exe") != std::string::npos) + binary_name = binary_name.substr(0, binary_name.length() - 4); +#endif // DOCTEST_PLATFORM_WINDOWS + + xml.startElement("doctest").writeAttribute("binary", binary_name); + if(opt.no_version == false) + xml.writeAttribute("version", DOCTEST_VERSION_STR); + + // only the consequential ones (TODO: filters) + xml.scopedElement("Options") + .writeAttribute("order_by", opt.order_by.c_str()) + .writeAttribute("rand_seed", opt.rand_seed) + .writeAttribute("first", opt.first) + .writeAttribute("last", opt.last) + .writeAttribute("abort_after", opt.abort_after) + .writeAttribute("subcase_filter_levels", opt.subcase_filter_levels) + .writeAttribute("case_sensitive", opt.case_sensitive) + .writeAttribute("no_throw", opt.no_throw) + .writeAttribute("no_skip", opt.no_skip); + } + + void test_run_end(const TestRunStats& p) override { + if(tc) // the TestSuite tag - only if there has been at least 1 test case + xml.endElement(); + + xml.scopedElement("OverallResultsAsserts") + .writeAttribute("successes", p.numAsserts - p.numAssertsFailed) + .writeAttribute("failures", p.numAssertsFailed); + + xml.startElement("OverallResultsTestCases") + .writeAttribute("successes", + p.numTestCasesPassingFilters - p.numTestCasesFailed) + .writeAttribute("failures", p.numTestCasesFailed); + if(opt.no_skipped_summary == false) + xml.writeAttribute("skipped", p.numTestCases - p.numTestCasesPassingFilters); + xml.endElement(); + + xml.endElement(); + } + + void test_case_start(const TestCaseData& in) override { + test_case_start_impl(in); + xml.ensureTagClosed(); + } + + void test_case_reenter(const TestCaseData&) override {} + + void test_case_end(const CurrentTestCaseStats& st) override { + xml.startElement("OverallResultsAsserts") + .writeAttribute("successes", + st.numAssertsCurrentTest - st.numAssertsFailedCurrentTest) + .writeAttribute("failures", st.numAssertsFailedCurrentTest) + .writeAttribute("test_case_success", st.testCaseSuccess); + if(opt.duration) + xml.writeAttribute("duration", st.seconds); + if(tc->m_expected_failures) + xml.writeAttribute("expected_failures", tc->m_expected_failures); + xml.endElement(); + + xml.endElement(); + } + + void test_case_exception(const TestCaseException& e) override { + DOCTEST_LOCK_MUTEX(mutex) + + xml.scopedElement("Exception") + .writeAttribute("crash", e.is_crash) + .writeText(e.error_string.c_str()); + } + + void subcase_start(const SubcaseSignature& in) override { + xml.startElement("SubCase") + .writeAttribute("name", in.m_name) + .writeAttribute("filename", skipPathFromFilename(in.m_file)) + .writeAttribute("line", line(in.m_line)); + xml.ensureTagClosed(); + } + + void subcase_end() override { xml.endElement(); } + + void log_assert(const AssertData& rb) override { + if(!rb.m_failed && !opt.success) + return; + + DOCTEST_LOCK_MUTEX(mutex) + + xml.startElement("Expression") + .writeAttribute("success", !rb.m_failed) + .writeAttribute("type", assertString(rb.m_at)) + .writeAttribute("filename", skipPathFromFilename(rb.m_file)) + .writeAttribute("line", line(rb.m_line)); + + xml.scopedElement("Original").writeText(rb.m_expr); + + if(rb.m_threw) + xml.scopedElement("Exception").writeText(rb.m_exception.c_str()); + + if(rb.m_at & assertType::is_throws_as) + xml.scopedElement("ExpectedException").writeText(rb.m_exception_type); + if(rb.m_at & assertType::is_throws_with) + xml.scopedElement("ExpectedExceptionString").writeText(rb.m_exception_string.c_str()); + if((rb.m_at & assertType::is_normal) && !rb.m_threw) + xml.scopedElement("Expanded").writeText(rb.m_decomp.c_str()); + + log_contexts(); + + xml.endElement(); + } + + void log_message(const MessageData& mb) override { + DOCTEST_LOCK_MUTEX(mutex) + + xml.startElement("Message") + .writeAttribute("type", failureString(mb.m_severity)) + .writeAttribute("filename", skipPathFromFilename(mb.m_file)) + .writeAttribute("line", line(mb.m_line)); + + xml.scopedElement("Text").writeText(mb.m_string.c_str()); + + log_contexts(); + + xml.endElement(); + } + + void test_case_skipped(const TestCaseData& in) override { + if(opt.no_skipped_summary == false) { + test_case_start_impl(in); + xml.writeAttribute("skipped", "true"); + xml.endElement(); + } + } + }; + + DOCTEST_REGISTER_REPORTER("xml", 0, XmlReporter); + + void fulltext_log_assert_to_stream(std::ostream& s, const AssertData& rb) { + if((rb.m_at & (assertType::is_throws_as | assertType::is_throws_with)) == + 0) //!OCLINT bitwise operator in conditional + s << Color::Cyan << assertString(rb.m_at) << "( " << rb.m_expr << " ) " + << Color::None; + + if(rb.m_at & assertType::is_throws) { //!OCLINT bitwise operator in conditional + s << (rb.m_threw ? "threw as expected!" : "did NOT throw at all!") << "\n"; + } else if((rb.m_at & assertType::is_throws_as) && + (rb.m_at & assertType::is_throws_with)) { //!OCLINT + s << Color::Cyan << assertString(rb.m_at) << "( " << rb.m_expr << ", \"" + << rb.m_exception_string.c_str() + << "\", " << rb.m_exception_type << " ) " << Color::None; + if(rb.m_threw) { + if(!rb.m_failed) { + s << "threw as expected!\n"; + } else { + s << "threw a DIFFERENT exception! (contents: " << rb.m_exception << ")\n"; + } + } else { + s << "did NOT throw at all!\n"; + } + } else if(rb.m_at & + assertType::is_throws_as) { //!OCLINT bitwise operator in conditional + s << Color::Cyan << assertString(rb.m_at) << "( " << rb.m_expr << ", " + << rb.m_exception_type << " ) " << Color::None + << (rb.m_threw ? (rb.m_threw_as ? "threw as expected!" : + "threw a DIFFERENT exception: ") : + "did NOT throw at all!") + << Color::Cyan << rb.m_exception << "\n"; + } else if(rb.m_at & + assertType::is_throws_with) { //!OCLINT bitwise operator in conditional + s << Color::Cyan << assertString(rb.m_at) << "( " << rb.m_expr << ", \"" + << rb.m_exception_string.c_str() + << "\" ) " << Color::None + << (rb.m_threw ? (!rb.m_failed ? "threw as expected!" : + "threw a DIFFERENT exception: ") : + "did NOT throw at all!") + << Color::Cyan << rb.m_exception << "\n"; + } else if(rb.m_at & assertType::is_nothrow) { //!OCLINT bitwise operator in conditional + s << (rb.m_threw ? "THREW exception: " : "didn't throw!") << Color::Cyan + << rb.m_exception << "\n"; + } else { + s << (rb.m_threw ? "THREW exception: " : + (!rb.m_failed ? "is correct!\n" : "is NOT correct!\n")); + if(rb.m_threw) + s << rb.m_exception << "\n"; + else + s << " values: " << assertString(rb.m_at) << "( " << rb.m_decomp << " )\n"; + } + } + + // TODO: + // - log_message() + // - respond to queries + // - honor remaining options + // - more attributes in tags + struct JUnitReporter : public IReporter + { + XmlWriter xml; + DOCTEST_DECLARE_MUTEX(mutex) + Timer timer; + std::vector deepestSubcaseStackNames; + + struct JUnitTestCaseData + { + static std::string getCurrentTimestamp() { + // Beware, this is not reentrant because of backward compatibility issues + // Also, UTC only, again because of backward compatibility (%z is C++11) + time_t rawtime; + std::time(&rawtime); + auto const timeStampSize = sizeof("2017-01-16T17:06:45Z"); + + std::tm timeInfo; +#ifdef DOCTEST_PLATFORM_WINDOWS + gmtime_s(&timeInfo, &rawtime); +#else // DOCTEST_PLATFORM_WINDOWS + gmtime_r(&rawtime, &timeInfo); +#endif // DOCTEST_PLATFORM_WINDOWS + + char timeStamp[timeStampSize]; + const char* const fmt = "%Y-%m-%dT%H:%M:%SZ"; + + std::strftime(timeStamp, timeStampSize, fmt, &timeInfo); + return std::string(timeStamp); + } + + struct JUnitTestMessage + { + JUnitTestMessage(const std::string& _message, const std::string& _type, const std::string& _details) + : message(_message), type(_type), details(_details) {} + + JUnitTestMessage(const std::string& _message, const std::string& _details) + : message(_message), type(), details(_details) {} + + std::string message, type, details; + }; + + struct JUnitTestCase + { + JUnitTestCase(const std::string& _classname, const std::string& _name) + : classname(_classname), name(_name), time(0), failures() {} + + std::string classname, name; + double time; + std::vector failures, errors; + }; + + void add(const std::string& classname, const std::string& name) { + testcases.emplace_back(classname, name); + } + + void appendSubcaseNamesToLastTestcase(std::vector nameStack) { + for(auto& curr: nameStack) + if(curr.size()) + testcases.back().name += std::string("/") + curr.c_str(); + } + + void addTime(double time) { + if(time < 1e-4) + time = 0; + testcases.back().time = time; + totalSeconds += time; + } + + void addFailure(const std::string& message, const std::string& type, const std::string& details) { + testcases.back().failures.emplace_back(message, type, details); + ++totalFailures; + } + + void addError(const std::string& message, const std::string& details) { + testcases.back().errors.emplace_back(message, details); + ++totalErrors; + } + + std::vector testcases; + double totalSeconds = 0; + int totalErrors = 0, totalFailures = 0; + }; + + JUnitTestCaseData testCaseData; + + // caching pointers/references to objects of these types - safe to do + const ContextOptions& opt; + const TestCaseData* tc = nullptr; + + JUnitReporter(const ContextOptions& co) + : xml(*co.cout) + , opt(co) {} + + unsigned line(unsigned l) const { return opt.no_line_numbers ? 0 : l; } + + // ========================================================================================= + // WHAT FOLLOWS ARE OVERRIDES OF THE VIRTUAL METHODS OF THE REPORTER INTERFACE + // ========================================================================================= + + void report_query(const QueryData&) override { + xml.writeDeclaration(); + } + + void test_run_start() override { + xml.writeDeclaration(); + } + + void test_run_end(const TestRunStats& p) override { + // remove .exe extension - mainly to have the same output on UNIX and Windows + std::string binary_name = skipPathFromFilename(opt.binary_name.c_str()); +#ifdef DOCTEST_PLATFORM_WINDOWS + if(binary_name.rfind(".exe") != std::string::npos) + binary_name = binary_name.substr(0, binary_name.length() - 4); +#endif // DOCTEST_PLATFORM_WINDOWS + xml.startElement("testsuites"); + xml.startElement("testsuite").writeAttribute("name", binary_name) + .writeAttribute("errors", testCaseData.totalErrors) + .writeAttribute("failures", testCaseData.totalFailures) + .writeAttribute("tests", p.numAsserts); + if(opt.no_time_in_output == false) { + xml.writeAttribute("time", testCaseData.totalSeconds); + xml.writeAttribute("timestamp", JUnitTestCaseData::getCurrentTimestamp()); + } + if(opt.no_version == false) + xml.writeAttribute("doctest_version", DOCTEST_VERSION_STR); + + for(const auto& testCase : testCaseData.testcases) { + xml.startElement("testcase") + .writeAttribute("classname", testCase.classname) + .writeAttribute("name", testCase.name); + if(opt.no_time_in_output == false) + xml.writeAttribute("time", testCase.time); + // This is not ideal, but it should be enough to mimic gtest's junit output. + xml.writeAttribute("status", "run"); + + for(const auto& failure : testCase.failures) { + xml.scopedElement("failure") + .writeAttribute("message", failure.message) + .writeAttribute("type", failure.type) + .writeText(failure.details, false); + } + + for(const auto& error : testCase.errors) { + xml.scopedElement("error") + .writeAttribute("message", error.message) + .writeText(error.details); + } + + xml.endElement(); + } + xml.endElement(); + xml.endElement(); + } + + void test_case_start(const TestCaseData& in) override { + testCaseData.add(skipPathFromFilename(in.m_file.c_str()), in.m_name); + timer.start(); + } + + void test_case_reenter(const TestCaseData& in) override { + testCaseData.addTime(timer.getElapsedSeconds()); + testCaseData.appendSubcaseNamesToLastTestcase(deepestSubcaseStackNames); + deepestSubcaseStackNames.clear(); + + timer.start(); + testCaseData.add(skipPathFromFilename(in.m_file.c_str()), in.m_name); + } + + void test_case_end(const CurrentTestCaseStats&) override { + testCaseData.addTime(timer.getElapsedSeconds()); + testCaseData.appendSubcaseNamesToLastTestcase(deepestSubcaseStackNames); + deepestSubcaseStackNames.clear(); + } + + void test_case_exception(const TestCaseException& e) override { + DOCTEST_LOCK_MUTEX(mutex) + testCaseData.addError("exception", e.error_string.c_str()); + } + + void subcase_start(const SubcaseSignature& in) override { + deepestSubcaseStackNames.push_back(in.m_name); + } + + void subcase_end() override {} + + void log_assert(const AssertData& rb) override { + if(!rb.m_failed) // report only failures & ignore the `success` option + return; + + DOCTEST_LOCK_MUTEX(mutex) + + std::ostringstream os; + os << skipPathFromFilename(rb.m_file) << (opt.gnu_file_line ? ":" : "(") + << line(rb.m_line) << (opt.gnu_file_line ? ":" : "):") << std::endl; + + fulltext_log_assert_to_stream(os, rb); + log_contexts(os); + testCaseData.addFailure(rb.m_decomp.c_str(), assertString(rb.m_at), os.str()); + } + + void log_message(const MessageData&) override {} + + void test_case_skipped(const TestCaseData&) override {} + + void log_contexts(std::ostringstream& s) { + int num_contexts = get_num_active_contexts(); + if(num_contexts) { + auto contexts = get_active_contexts(); + + s << " logged: "; + for(int i = 0; i < num_contexts; ++i) { + s << (i == 0 ? "" : " "); + contexts[i]->stringify(&s); + s << std::endl; + } + } + } + }; + + DOCTEST_REGISTER_REPORTER("junit", 0, JUnitReporter); + + struct Whitespace + { + int nrSpaces; + explicit Whitespace(int nr) + : nrSpaces(nr) {} + }; - void printToDebugConsole(const String& text) { - if(isDebuggerActive()) - myOutputDebugString(text); + std::ostream& operator<<(std::ostream& out, const Whitespace& ws) { + if(ws.nrSpaces != 0) + out << std::setw(ws.nrSpaces) << ' '; + return out; } - void addFailedAssert(assertType::Enum at) { - if((at & assertType::is_warn) == 0) { //!OCLINT bitwise operator in conditional - contextState->numFailedAssertions++; - contextState->numFailedAssertionsForCurrentTestcase++; - contextState->hasCurrentTestFailed = true; + struct ConsoleReporter : public IReporter + { + std::ostream& s; + bool hasLoggedCurrentTestStart; + std::vector subcasesStack; + size_t currentSubcaseLevel; + DOCTEST_DECLARE_MUTEX(mutex) + + // caching pointers/references to objects of these types - safe to do + const ContextOptions& opt; + const TestCaseData* tc; + + ConsoleReporter(const ContextOptions& co) + : s(*co.cout) + , opt(co) {} + + ConsoleReporter(const ContextOptions& co, std::ostream& ostr) + : s(ostr) + , opt(co) {} + + // ========================================================================================= + // WHAT FOLLOWS ARE HELPERS USED BY THE OVERRIDES OF THE VIRTUAL METHODS OF THE INTERFACE + // ========================================================================================= + + void separator_to_stream() { + s << Color::Yellow + << "===============================================================================" + "\n"; } - } - std::ostream& operator<<(std::ostream& s, const std::vector& contexts) { - if(!contexts.empty()) - s << Color::None << " logged: "; - for(size_t i = 0; i < contexts.size(); ++i) { - s << (i == 0 ? "" : " "); - contexts[i]->build(&s); + const char* getSuccessOrFailString(bool success, assertType::Enum at, + const char* success_str) { + if(success) + return success_str; + return failureString(at); + } + + Color::Enum getSuccessOrFailColor(bool success, assertType::Enum at) { + return success ? Color::BrightGreen : + (at & assertType::is_warn) ? Color::Yellow : Color::Red; + } + + void successOrFailColoredStringToStream(bool success, assertType::Enum at, + const char* success_str = "SUCCESS") { + s << getSuccessOrFailColor(success, at) + << getSuccessOrFailString(success, at, success_str) << ": "; + } + + void log_contexts() { + int num_contexts = get_num_active_contexts(); + if(num_contexts) { + auto contexts = get_active_contexts(); + + s << Color::None << " logged: "; + for(int i = 0; i < num_contexts; ++i) { + s << (i == 0 ? "" : " "); + contexts[i]->stringify(&s); + s << "\n"; + } + } + s << "\n"; } - s << "\n"; - return s; - } - void logTestStart(std::ostream& s, const TestCase& tc) { - separator_to_stream(s); - file_line_to_stream(s, tc.m_file, tc.m_line, "\n"); - if(tc.m_description) - s << Color::Yellow << "DESCRIPTION: " << Color::None << tc.m_description << "\n"; - if(tc.m_test_suite && tc.m_test_suite[0] != '\0') - s << Color::Yellow << "TEST SUITE: " << Color::None << tc.m_test_suite << "\n"; - if(strncmp(tc.m_name, " Scenario:", 11) != 0) - s << Color::None << "TEST CASE: "; - s << Color::None << tc.m_name << "\n"; - - std::vector& subcasesStack = contextState->subcasesStack; - for(unsigned i = 0; i < subcasesStack.size(); ++i) - if(subcasesStack[i].m_signature.m_name[0] != '\0') - s << " " << subcasesStack[i].m_signature.m_name << "\n"; - - s << "\n"; - } + // this was requested to be made virtual so users could override it + virtual void file_line_to_stream(const char* file, int line, + const char* tail = "") { + s << Color::LightGrey << skipPathFromFilename(file) << (opt.gnu_file_line ? ":" : "(") + << (opt.no_line_numbers ? 0 : line) // 0 or the real num depending on the option + << (opt.gnu_file_line ? ":" : "):") << tail; + } + + void logTestStart() { + if(hasLoggedCurrentTestStart) + return; - void logTestEnd() {} + separator_to_stream(); + file_line_to_stream(tc->m_file.c_str(), tc->m_line, "\n"); + if(tc->m_description) + s << Color::Yellow << "DESCRIPTION: " << Color::None << tc->m_description << "\n"; + if(tc->m_test_suite && tc->m_test_suite[0] != '\0') + s << Color::Yellow << "TEST SUITE: " << Color::None << tc->m_test_suite << "\n"; + if(strncmp(tc->m_name, " Scenario:", 11) != 0) + s << Color::Yellow << "TEST CASE: "; + s << Color::None << tc->m_name << "\n"; + + for(size_t i = 0; i < currentSubcaseLevel; ++i) { + if(subcasesStack[i].m_name[0] != '\0') + s << " " << subcasesStack[i].m_name << "\n"; + } + + if(currentSubcaseLevel != subcasesStack.size()) { + s << Color::Yellow << "\nDEEPEST SUBCASE STACK REACHED (DIFFERENT FROM THE CURRENT ONE):\n" << Color::None; + for(size_t i = 0; i < subcasesStack.size(); ++i) { + if(subcasesStack[i].m_name[0] != '\0') + s << " " << subcasesStack[i].m_name << "\n"; + } + } - void logTestException_impl(std::ostream& s, const TestCase& tc, const String& str, bool crash) { - file_line_to_stream(s, tc.m_file, tc.m_line, " "); - successOrFailColoredStringToStream(s, false, - crash ? assertType::is_require : assertType::is_check); - s << Color::Red << (crash ? "test case CRASHED: " : "test case THREW exception: ") - << Color::Cyan << str << "\n"; + s << "\n"; - if(!contextState->exceptionalContexts.empty()) { - s << Color::None << " logged: "; - for(size_t i = contextState->exceptionalContexts.size(); i > 0; --i) - s << (i == contextState->exceptionalContexts.size() ? "" : " ") - << contextState->exceptionalContexts[i - 1] << "\n"; + hasLoggedCurrentTestStart = true; } - s << "\n"; - } - void logTestException(const TestCase& tc, const String& what, bool crash) { - logTestException_impl(std::cout, tc, what, crash); - DOCTEST_PRINT_TO_OUTPUT_WINDOW_IN_IDE_BEGIN; - logTestException_impl(oss, tc, what, crash); - DOCTEST_PRINT_TO_OUTPUT_WINDOW_IN_IDE_END; - } + void printVersion() { + if(opt.no_version == false) + s << Color::Cyan << "[doctest] " << Color::None << "doctest version is \"" + << DOCTEST_VERSION_STR << "\"\n"; + } -#if defined(DOCTEST_CONFIG_POSIX_SIGNALS) || defined(DOCTEST_CONFIG_WINDOWS_SEH) - void reportFatal(const std::string& message) { - DOCTEST_LOG_START(std::cout); + void printIntro() { + if(opt.no_intro == false) { + printVersion(); + s << Color::Cyan << "[doctest] " << Color::None + << "run with \"--" DOCTEST_OPTIONS_PREFIX_DISPLAY "help\" for options\n"; + } + } - contextState->numAssertions += contextState->numAssertionsForCurrentTestcase; - logTestException(*contextState->currentTest, message.c_str(), true); - logTestEnd(); - contextState->numFailed++; + void printHelp() { + int sizePrefixDisplay = static_cast(strlen(DOCTEST_OPTIONS_PREFIX_DISPLAY)); + printVersion(); + // clang-format off + s << Color::Cyan << "[doctest]\n" << Color::None; + s << Color::Cyan << "[doctest] " << Color::None; + s << "boolean values: \"1/on/yes/true\" or \"0/off/no/false\"\n"; + s << Color::Cyan << "[doctest] " << Color::None; + s << "filter values: \"str1,str2,str3\" (comma separated strings)\n"; + s << Color::Cyan << "[doctest]\n" << Color::None; + s << Color::Cyan << "[doctest] " << Color::None; + s << "filters use wildcards for matching strings\n"; + s << Color::Cyan << "[doctest] " << Color::None; + s << "something passes a filter if any of the strings in a filter matches\n"; +#ifndef DOCTEST_CONFIG_NO_UNPREFIXED_OPTIONS + s << Color::Cyan << "[doctest]\n" << Color::None; + s << Color::Cyan << "[doctest] " << Color::None; + s << "ALL FLAGS, OPTIONS AND FILTERS ALSO AVAILABLE WITH A \"" DOCTEST_CONFIG_OPTIONS_PREFIX "\" PREFIX!!!\n"; +#endif + s << Color::Cyan << "[doctest]\n" << Color::None; + s << Color::Cyan << "[doctest] " << Color::None; + s << "Query flags - the program quits after them. Available:\n\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "?, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "help, -" DOCTEST_OPTIONS_PREFIX_DISPLAY "h " + << Whitespace(sizePrefixDisplay*0) << "prints this message\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "v, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "version " + << Whitespace(sizePrefixDisplay*1) << "prints the version\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "c, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "count " + << Whitespace(sizePrefixDisplay*1) << "prints the number of matching tests\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "ltc, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "list-test-cases " + << Whitespace(sizePrefixDisplay*1) << "lists all matching tests by name\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "lts, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "list-test-suites " + << Whitespace(sizePrefixDisplay*1) << "lists all matching test suites\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "lr, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "list-reporters " + << Whitespace(sizePrefixDisplay*1) << "lists all registered reporters\n\n"; + // ================================================================================== << 79 + s << Color::Cyan << "[doctest] " << Color::None; + s << "The available / options/filters are:\n\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "tc, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "test-case= " + << Whitespace(sizePrefixDisplay*1) << "filters tests by their name\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "tce, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "test-case-exclude= " + << Whitespace(sizePrefixDisplay*1) << "filters OUT tests by their name\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "sf, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "source-file= " + << Whitespace(sizePrefixDisplay*1) << "filters tests by their file\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "sfe, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "source-file-exclude= " + << Whitespace(sizePrefixDisplay*1) << "filters OUT tests by their file\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "ts, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "test-suite= " + << Whitespace(sizePrefixDisplay*1) << "filters tests by their test suite\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "tse, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "test-suite-exclude= " + << Whitespace(sizePrefixDisplay*1) << "filters OUT tests by their test suite\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "sc, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "subcase= " + << Whitespace(sizePrefixDisplay*1) << "filters subcases by their name\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "sce, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "subcase-exclude= " + << Whitespace(sizePrefixDisplay*1) << "filters OUT subcases by their name\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "r, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "reporters= " + << Whitespace(sizePrefixDisplay*1) << "reporters to use (console is default)\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "o, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "out= " + << Whitespace(sizePrefixDisplay*1) << "output filename\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "ob, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "order-by= " + << Whitespace(sizePrefixDisplay*1) << "how the tests should be ordered\n"; + s << Whitespace(sizePrefixDisplay*3) << " - [file/suite/name/rand/none]\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "rs, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "rand-seed= " + << Whitespace(sizePrefixDisplay*1) << "seed for random ordering\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "f, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "first= " + << Whitespace(sizePrefixDisplay*1) << "the first test passing the filters to\n"; + s << Whitespace(sizePrefixDisplay*3) << " execute - for range-based execution\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "l, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "last= " + << Whitespace(sizePrefixDisplay*1) << "the last test passing the filters to\n"; + s << Whitespace(sizePrefixDisplay*3) << " execute - for range-based execution\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "aa, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "abort-after= " + << Whitespace(sizePrefixDisplay*1) << "stop after failed assertions\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "scfl,--" DOCTEST_OPTIONS_PREFIX_DISPLAY "subcase-filter-levels= " + << Whitespace(sizePrefixDisplay*1) << "apply filters for the first levels\n"; + s << Color::Cyan << "\n[doctest] " << Color::None; + s << "Bool options - can be used like flags and true is assumed. Available:\n\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "s, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "success= " + << Whitespace(sizePrefixDisplay*1) << "include successful assertions in output\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "cs, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "case-sensitive= " + << Whitespace(sizePrefixDisplay*1) << "filters being treated as case sensitive\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "e, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "exit= " + << Whitespace(sizePrefixDisplay*1) << "exits after the tests finish\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "d, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "duration= " + << Whitespace(sizePrefixDisplay*1) << "prints the time duration of each test\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "m, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "minimal= " + << Whitespace(sizePrefixDisplay*1) << "minimal console output (only failures)\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "q, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "quiet= " + << Whitespace(sizePrefixDisplay*1) << "no console output\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "nt, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "no-throw= " + << Whitespace(sizePrefixDisplay*1) << "skips exceptions-related assert checks\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "ne, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "no-exitcode= " + << Whitespace(sizePrefixDisplay*1) << "returns (or exits) always with success\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "nr, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "no-run= " + << Whitespace(sizePrefixDisplay*1) << "skips all runtime doctest operations\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "ni, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "no-intro= " + << Whitespace(sizePrefixDisplay*1) << "omit the framework intro in the output\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "nv, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "no-version= " + << Whitespace(sizePrefixDisplay*1) << "omit the framework version in the output\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "nc, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "no-colors= " + << Whitespace(sizePrefixDisplay*1) << "disables colors in output\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "fc, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "force-colors= " + << Whitespace(sizePrefixDisplay*1) << "use colors even when not in a tty\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "nb, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "no-breaks= " + << Whitespace(sizePrefixDisplay*1) << "disables breakpoints in debuggers\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "ns, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "no-skip= " + << Whitespace(sizePrefixDisplay*1) << "don't skip test cases marked as skip\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "gfl, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "gnu-file-line= " + << Whitespace(sizePrefixDisplay*1) << ":n: vs (n): for line numbers in output\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "npf, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "no-path-filenames= " + << Whitespace(sizePrefixDisplay*1) << "only filenames and no paths in output\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "nln, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "no-line-numbers= " + << Whitespace(sizePrefixDisplay*1) << "0 instead of real line numbers in output\n"; + // ================================================================================== << 79 + // clang-format on - printSummary(std::cout); - } -#endif // DOCTEST_CONFIG_POSIX_SIGNALS || DOCTEST_CONFIG_WINDOWS_SEH + s << Color::Cyan << "\n[doctest] " << Color::None; + s << "for more information visit the project documentation\n\n"; + } - void logAssert_impl(std::ostream& s, bool passed, const String& dec, bool threw, - const String& ex, const char* expr, assertType::Enum at, const char* file, - int line) { - file_line_to_stream(s, file, line, " "); - successOrFailColoredStringToStream(s, passed, at); - s << Color::Cyan << assertString(at) << "( " << expr << " ) " << Color::None - << (threw ? "THREW exception: " : (passed ? "is correct!\n" : "is NOT correct!\n")); - if(threw) - s << ex << "\n"; - else - s << " values: " << assertString(at) << "( " << dec << " )\n"; - s << contextState->contexts; - } + void printRegisteredReporters() { + printVersion(); + auto printReporters = [this] (const reporterMap& reporters, const char* type) { + if(reporters.size()) { + s << Color::Cyan << "[doctest] " << Color::None << "listing all registered " << type << "\n"; + for(auto& curr : reporters) + s << "priority: " << std::setw(5) << curr.first.first + << " name: " << curr.first.second << "\n"; + } + }; + printReporters(getListeners(), "listeners"); + printReporters(getReporters(), "reporters"); + } - void logAssert(bool passed, const String& dec, bool threw, const String& ex, const char* expr, - assertType::Enum at, const char* file, int line) { - logAssert_impl(std::cout, passed, dec, threw, ex, expr, at, file, line); - DOCTEST_PRINT_TO_OUTPUT_WINDOW_IN_IDE_BEGIN; - logAssert_impl(oss, passed, dec, threw, ex, expr, at, file, line); - DOCTEST_PRINT_TO_OUTPUT_WINDOW_IN_IDE_END; - } + // ========================================================================================= + // WHAT FOLLOWS ARE OVERRIDES OF THE VIRTUAL METHODS OF THE REPORTER INTERFACE + // ========================================================================================= + + void report_query(const QueryData& in) override { + if(opt.version) { + printVersion(); + } else if(opt.help) { + printHelp(); + } else if(opt.list_reporters) { + printRegisteredReporters(); + } else if(opt.count || opt.list_test_cases) { + if(opt.list_test_cases) { + s << Color::Cyan << "[doctest] " << Color::None + << "listing all test case names\n"; + separator_to_stream(); + } - void logAssertThrows_impl(std::ostream& s, bool threw, const char* expr, assertType::Enum at, - const char* file, int line) { - file_line_to_stream(s, file, line, " "); - successOrFailColoredStringToStream(s, threw, at); - s << Color::Cyan << assertString(at) << "( " << expr << " ) " << Color::None - << (threw ? "threw as expected!" : "did NOT throw at all!") << "\n"; - s << contextState->contexts; - } + for(unsigned i = 0; i < in.num_data; ++i) + s << Color::None << in.data[i]->m_name << "\n"; - void logAssertThrows(bool threw, const char* expr, assertType::Enum at, const char* file, - int line) { - logAssertThrows_impl(std::cout, threw, expr, at, file, line); - DOCTEST_PRINT_TO_OUTPUT_WINDOW_IN_IDE_BEGIN; - logAssertThrows_impl(oss, threw, expr, at, file, line); - DOCTEST_PRINT_TO_OUTPUT_WINDOW_IN_IDE_END; - } + separator_to_stream(); - void logAssertThrowsAs_impl(std::ostream& s, bool threw, bool threw_as, const char* as, - const String& ex, const char* expr, assertType::Enum at, - const char* file, int line) { - file_line_to_stream(s, file, line, " "); - successOrFailColoredStringToStream(s, threw_as, at); - s << Color::Cyan << assertString(at) << "( " << expr << ", " << as << " ) " << Color::None - << (threw ? (threw_as ? "threw as expected!" : "threw a DIFFERENT exception: ") : - "did NOT throw at all!") - << Color::Cyan << ex << "\n"; - s << contextState->contexts; - } + s << Color::Cyan << "[doctest] " << Color::None + << "unskipped test cases passing the current filters: " + << g_cs->numTestCasesPassingFilters << "\n"; - void logAssertThrowsAs(bool threw, bool threw_as, const char* as, const String& ex, - const char* expr, assertType::Enum at, const char* file, int line) { - logAssertThrowsAs_impl(std::cout, threw, threw_as, as, ex, expr, at, file, line); - DOCTEST_PRINT_TO_OUTPUT_WINDOW_IN_IDE_BEGIN; - logAssertThrowsAs_impl(oss, threw, threw_as, as, ex, expr, at, file, line); - DOCTEST_PRINT_TO_OUTPUT_WINDOW_IN_IDE_END; - } + } else if(opt.list_test_suites) { + s << Color::Cyan << "[doctest] " << Color::None << "listing all test suites\n"; + separator_to_stream(); - void logAssertNothrow_impl(std::ostream& s, bool threw, const String& ex, const char* expr, - assertType::Enum at, const char* file, int line) { - file_line_to_stream(s, file, line, " "); - successOrFailColoredStringToStream(s, !threw, at); - s << Color::Cyan << assertString(at) << "( " << expr << " ) " << Color::None - << (threw ? "THREW exception: " : "didn't throw!") << Color::Cyan << ex << "\n"; - s << contextState->contexts; - } + for(unsigned i = 0; i < in.num_data; ++i) + s << Color::None << in.data[i]->m_test_suite << "\n"; - void logAssertNothrow(bool threw, const String& ex, const char* expr, assertType::Enum at, - const char* file, int line) { - logAssertNothrow_impl(std::cout, threw, ex, expr, at, file, line); - DOCTEST_PRINT_TO_OUTPUT_WINDOW_IN_IDE_BEGIN; - logAssertNothrow_impl(oss, threw, ex, expr, at, file, line); - DOCTEST_PRINT_TO_OUTPUT_WINDOW_IN_IDE_END; - } + separator_to_stream(); - ResultBuilder::ResultBuilder(assertType::Enum at, const char* file, int line, const char* expr, - const char* exception_type) - : m_assert_type(at) - , m_file(file) - , m_line(line) - , m_expr(expr) - , m_exception_type(exception_type) - , m_threw(false) - , m_threw_as(false) - , m_failed(false) { -#if DOCTEST_MSVC - if(m_expr[0] == ' ') // this happens when variadic macros are disabled under MSVC - ++m_expr; -#endif // MSVC - } + s << Color::Cyan << "[doctest] " << Color::None + << "unskipped test cases passing the current filters: " + << g_cs->numTestCasesPassingFilters << "\n"; + s << Color::Cyan << "[doctest] " << Color::None + << "test suites with unskipped test cases passing the current filters: " + << g_cs->numTestSuitesPassingFilters << "\n"; + } + } - ResultBuilder::~ResultBuilder() {} + void test_run_start() override { + if(!opt.minimal) + printIntro(); + } - void ResultBuilder::unexpectedExceptionOccurred() { - m_threw = true; + void test_run_end(const TestRunStats& p) override { + if(opt.minimal && p.numTestCasesFailed == 0) + return; - m_exception = translateActiveException(); - } + separator_to_stream(); + s << std::dec; + + auto totwidth = int(std::ceil(log10((std::max(p.numTestCasesPassingFilters, static_cast(p.numAsserts))) + 1))); + auto passwidth = int(std::ceil(log10((std::max(p.numTestCasesPassingFilters - p.numTestCasesFailed, static_cast(p.numAsserts - p.numAssertsFailed))) + 1))); + auto failwidth = int(std::ceil(log10((std::max(p.numTestCasesFailed, static_cast(p.numAssertsFailed))) + 1))); + const bool anythingFailed = p.numTestCasesFailed > 0 || p.numAssertsFailed > 0; + s << Color::Cyan << "[doctest] " << Color::None << "test cases: " << std::setw(totwidth) + << p.numTestCasesPassingFilters << " | " + << ((p.numTestCasesPassingFilters == 0 || anythingFailed) ? Color::None : + Color::Green) + << std::setw(passwidth) << p.numTestCasesPassingFilters - p.numTestCasesFailed << " passed" + << Color::None << " | " << (p.numTestCasesFailed > 0 ? Color::Red : Color::None) + << std::setw(failwidth) << p.numTestCasesFailed << " failed" << Color::None << " |"; + if(opt.no_skipped_summary == false) { + const int numSkipped = p.numTestCases - p.numTestCasesPassingFilters; + s << " " << (numSkipped == 0 ? Color::None : Color::Yellow) << numSkipped + << " skipped" << Color::None; + } + s << "\n"; + s << Color::Cyan << "[doctest] " << Color::None << "assertions: " << std::setw(totwidth) + << p.numAsserts << " | " + << ((p.numAsserts == 0 || anythingFailed) ? Color::None : Color::Green) + << std::setw(passwidth) << (p.numAsserts - p.numAssertsFailed) << " passed" << Color::None + << " | " << (p.numAssertsFailed > 0 ? Color::Red : Color::None) << std::setw(failwidth) + << p.numAssertsFailed << " failed" << Color::None << " |\n"; + s << Color::Cyan << "[doctest] " << Color::None + << "Status: " << (p.numTestCasesFailed > 0 ? Color::Red : Color::Green) + << ((p.numTestCasesFailed > 0) ? "FAILURE!" : "SUCCESS!") << Color::None << std::endl; + } - bool ResultBuilder::log() { - if((m_assert_type & assertType::is_warn) == 0) //!OCLINT bitwise operator in conditional - contextState->numAssertionsForCurrentTestcase++; + void test_case_start(const TestCaseData& in) override { + hasLoggedCurrentTestStart = false; + tc = ∈ + subcasesStack.clear(); + currentSubcaseLevel = 0; + } - if(m_assert_type & assertType::is_throws) { //!OCLINT bitwise operator in conditional - m_failed = !m_threw; - } else if(m_assert_type & //!OCLINT bitwise operator in conditional - assertType::is_throws_as) { - m_failed = !m_threw_as; - } else if(m_assert_type & //!OCLINT bitwise operator in conditional - assertType::is_nothrow) { - m_failed = m_threw; - } else { - m_failed = m_result; + void test_case_reenter(const TestCaseData&) override { + subcasesStack.clear(); } - if(m_failed || contextState->success) { - DOCTEST_LOG_START(std::cout); + void test_case_end(const CurrentTestCaseStats& st) override { + if(tc->m_no_output) + return; - if(m_assert_type & assertType::is_throws) { //!OCLINT bitwise operator in conditional - logAssertThrows(m_threw, m_expr, m_assert_type, m_file, m_line); - } else if(m_assert_type & //!OCLINT bitwise operator in conditional - assertType::is_throws_as) { - logAssertThrowsAs(m_threw, m_threw_as, m_exception_type, m_exception, m_expr, - m_assert_type, m_file, m_line); - } else if(m_assert_type & //!OCLINT bitwise operator in conditional - assertType::is_nothrow) { - logAssertNothrow(m_threw, m_exception, m_expr, m_assert_type, m_file, m_line); - } else { - logAssert(m_result.m_passed, m_result.m_decomposition, m_threw, m_exception, m_expr, - m_assert_type, m_file, m_line); + // log the preamble of the test case only if there is something + // else to print - something other than that an assert has failed + if(opt.duration || + (st.failure_flags && st.failure_flags != static_cast(TestCaseFailureReason::AssertFailure))) + logTestStart(); + + if(opt.duration) + s << Color::None << std::setprecision(6) << std::fixed << st.seconds + << " s: " << tc->m_name << "\n"; + + if(st.failure_flags & TestCaseFailureReason::Timeout) + s << Color::Red << "Test case exceeded time limit of " << std::setprecision(6) + << std::fixed << tc->m_timeout << "!\n"; + + if(st.failure_flags & TestCaseFailureReason::ShouldHaveFailedButDidnt) { + s << Color::Red << "Should have failed but didn't! Marking it as failed!\n"; + } else if(st.failure_flags & TestCaseFailureReason::ShouldHaveFailedAndDid) { + s << Color::Yellow << "Failed as expected so marking it as not failed\n"; + } else if(st.failure_flags & TestCaseFailureReason::CouldHaveFailedAndDid) { + s << Color::Yellow << "Allowed to fail so marking it as not failed\n"; + } else if(st.failure_flags & TestCaseFailureReason::DidntFailExactlyNumTimes) { + s << Color::Red << "Didn't fail exactly " << tc->m_expected_failures + << " times so marking it as failed!\n"; + } else if(st.failure_flags & TestCaseFailureReason::FailedExactlyNumTimes) { + s << Color::Yellow << "Failed exactly " << tc->m_expected_failures + << " times as expected so marking it as not failed!\n"; } + if(st.failure_flags & TestCaseFailureReason::TooManyFailedAsserts) { + s << Color::Red << "Aborting - too many failed asserts!\n"; + } + s << Color::None; // lgtm [cpp/useless-expression] } - if(m_failed) - addFailedAssert(m_assert_type); + void test_case_exception(const TestCaseException& e) override { + DOCTEST_LOCK_MUTEX(mutex) + if(tc->m_no_output) + return; + + logTestStart(); + + file_line_to_stream(tc->m_file.c_str(), tc->m_line, " "); + successOrFailColoredStringToStream(false, e.is_crash ? assertType::is_require : + assertType::is_check); + s << Color::Red << (e.is_crash ? "test case CRASHED: " : "test case THREW exception: ") + << Color::Cyan << e.error_string << "\n"; + + int num_stringified_contexts = get_num_stringified_contexts(); + if(num_stringified_contexts) { + auto stringified_contexts = get_stringified_contexts(); + s << Color::None << " logged: "; + for(int i = num_stringified_contexts; i > 0; --i) { + s << (i == num_stringified_contexts ? "" : " ") + << stringified_contexts[i - 1] << "\n"; + } + } + s << "\n" << Color::None; + } - return m_failed && isDebuggerActive() && !contextState->no_breaks; // break into debugger - } + void subcase_start(const SubcaseSignature& subc) override { + subcasesStack.push_back(subc); + ++currentSubcaseLevel; + hasLoggedCurrentTestStart = false; + } - void ResultBuilder::react() const { - if(m_failed && checkIfShouldThrow(m_assert_type)) - throwException(); - } + void subcase_end() override { + --currentSubcaseLevel; + hasLoggedCurrentTestStart = false; + } - MessageBuilder::MessageBuilder(const char* file, int line, assertType::Enum severity) - : m_stream(createStream()) - , m_file(file) - , m_line(line) - , m_severity(severity) {} - - void MessageBuilder::log(std::ostream& s) { - file_line_to_stream(s, m_file, m_line, " "); - s << getSuccessOrFailColor(false, m_severity) - << getSuccessOrFailString(m_severity & assertType::is_warn, m_severity, "MESSAGE: "); - s << Color::None << getStreamResult(m_stream) << "\n"; - s << contextState->contexts; - } + void log_assert(const AssertData& rb) override { + if((!rb.m_failed && !opt.success) || tc->m_no_output) + return; - bool MessageBuilder::log() { - DOCTEST_LOG_START(std::cout); + DOCTEST_LOCK_MUTEX(mutex) - log(std::cout); - DOCTEST_PRINT_TO_OUTPUT_WINDOW_IN_IDE_BEGIN; - log(oss); - DOCTEST_PRINT_TO_OUTPUT_WINDOW_IN_IDE_END; - const bool isWarn = m_severity & assertType::is_warn; + logTestStart(); - // warn is just a message in this context so we dont treat it as an assert - if(!isWarn) { - contextState->numAssertionsForCurrentTestcase++; - addFailedAssert(m_severity); + file_line_to_stream(rb.m_file, rb.m_line, " "); + successOrFailColoredStringToStream(!rb.m_failed, rb.m_at); + + fulltext_log_assert_to_stream(s, rb); + + log_contexts(); } - return isDebuggerActive() && !contextState->no_breaks && !isWarn; // break into debugger - } + void log_message(const MessageData& mb) override { + if(tc->m_no_output) + return; - void MessageBuilder::react() { - if(m_severity & assertType::is_require) //!OCLINT bitwise operator in conditional - throwException(); - } + DOCTEST_LOCK_MUTEX(mutex) - MessageBuilder::~MessageBuilder() { freeStream(m_stream); } - - // the implementation of parseFlag() - bool parseFlagImpl(int argc, const char* const* argv, const char* pattern) { - for(int i = argc - 1; i >= 0; --i) { - const char* temp = std::strstr(argv[i], pattern); - if(temp && strlen(temp) == strlen(pattern)) { - // eliminate strings in which the chars before the option are not '-' - bool noBadCharsFound = true; //!OCLINT prefer early exits and continue - while(temp != argv[i]) { - if(*--temp != '-') { - noBadCharsFound = false; - break; - } - } - if(noBadCharsFound && argv[i][0] == '-') - return true; - } + logTestStart(); + + file_line_to_stream(mb.m_file, mb.m_line, " "); + s << getSuccessOrFailColor(false, mb.m_severity) + << getSuccessOrFailString(mb.m_severity & assertType::is_warn, mb.m_severity, + "MESSAGE") << ": "; + s << Color::None << mb.m_string << "\n"; + log_contexts(); } - return false; - } - // locates a flag on the command line - bool parseFlag(int argc, const char* const* argv, const char* pattern) { -#ifndef DOCTEST_CONFIG_NO_UNPREFIXED_OPTIONS - if(!parseFlagImpl(argc, argv, pattern)) - return parseFlagImpl(argc, argv, pattern + 3); // 3 for "dt-" - return true; -#else // DOCTEST_CONFIG_NO_UNPREFIXED_OPTIONS - return parseFlagImpl(argc, argv, pattern); -#endif // DOCTEST_CONFIG_NO_UNPREFIXED_OPTIONS + void test_case_skipped(const TestCaseData&) override {} + }; + + DOCTEST_REGISTER_REPORTER("console", 0, ConsoleReporter); + +#ifdef DOCTEST_PLATFORM_WINDOWS + struct DebugOutputWindowReporter : public ConsoleReporter + { + DOCTEST_THREAD_LOCAL static std::ostringstream oss; + + DebugOutputWindowReporter(const ContextOptions& co) + : ConsoleReporter(co, oss) {} + +#define DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(func, type, arg) \ + void func(type arg) override { \ + bool with_col = g_no_colors; \ + g_no_colors = false; \ + ConsoleReporter::func(arg); \ + if(oss.tellp() != std::streampos{}) { \ + DOCTEST_OUTPUT_DEBUG_STRING(oss.str().c_str()); \ + oss.str(""); \ + } \ + g_no_colors = with_col; \ } + DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(test_run_start, DOCTEST_EMPTY, DOCTEST_EMPTY) + DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(test_run_end, const TestRunStats&, in) + DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(test_case_start, const TestCaseData&, in) + DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(test_case_reenter, const TestCaseData&, in) + DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(test_case_end, const CurrentTestCaseStats&, in) + DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(test_case_exception, const TestCaseException&, in) + DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(subcase_start, const SubcaseSignature&, in) + DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(subcase_end, DOCTEST_EMPTY, DOCTEST_EMPTY) + DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(log_assert, const AssertData&, in) + DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(log_message, const MessageData&, in) + DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(test_case_skipped, const TestCaseData&, in) + }; + + DOCTEST_THREAD_LOCAL std::ostringstream DebugOutputWindowReporter::oss; +#endif // DOCTEST_PLATFORM_WINDOWS + // the implementation of parseOption() - bool parseOptionImpl(int argc, const char* const* argv, const char* pattern, String& res) { - for(int i = argc - 1; i >= 0; --i) { - const char* temp = std::strstr(argv[i], pattern); - if(temp) { //!OCLINT prefer early exits and continue + bool parseOptionImpl(int argc, const char* const* argv, const char* pattern, String* value) { + // going from the end to the beginning and stopping on the first occurrence from the end + for(int i = argc; i > 0; --i) { + auto index = i - 1; + auto temp = std::strstr(argv[index], pattern); + if(temp && (value || strlen(temp) == strlen(pattern))) { //!OCLINT prefer early exits and continue // eliminate matches in which the chars before the option are not '-' - bool noBadCharsFound = true; - const char* curr = argv[i]; + bool noBadCharsFound = true; + auto curr = argv[index]; while(curr != temp) { if(*curr++ != '-') { noBadCharsFound = false; break; } } - if(noBadCharsFound && argv[i][0] == '-') { - temp += strlen(pattern); - const unsigned len = strlen(temp); - if(len) { - res = temp; + if(noBadCharsFound && argv[index][0] == '-') { + if(value) { + // parsing the value of an option + temp += strlen(pattern); + const unsigned len = strlen(temp); + if(len) { + *value = temp; + return true; + } + } else { + // just a flag - no value return true; } } @@ -4873,33 +6409,64 @@ namespace detail } // parses an option and returns the string after the '=' character - bool parseOption(int argc, const char* const* argv, const char* pattern, String& res, + bool parseOption(int argc, const char* const* argv, const char* pattern, String* value = nullptr, const String& defaultVal = String()) { - res = defaultVal; + if(value) + *value = defaultVal; #ifndef DOCTEST_CONFIG_NO_UNPREFIXED_OPTIONS - if(!parseOptionImpl(argc, argv, pattern, res)) - return parseOptionImpl(argc, argv, pattern + 3, res); // 3 for "dt-" - return true; -#else // DOCTEST_CONFIG_NO_UNPREFIXED_OPTIONS - return parseOptionImpl(argc, argv, pattern, res); + // offset (normally 3 for "dt-") to skip prefix + if(parseOptionImpl(argc, argv, pattern + strlen(DOCTEST_CONFIG_OPTIONS_PREFIX), value)) + return true; #endif // DOCTEST_CONFIG_NO_UNPREFIXED_OPTIONS + return parseOptionImpl(argc, argv, pattern, value); + } + + // locates a flag on the command line + bool parseFlag(int argc, const char* const* argv, const char* pattern) { + return parseOption(argc, argv, pattern); } // parses a comma separated list of words after a pattern in one of the arguments in argv bool parseCommaSepArgs(int argc, const char* const* argv, const char* pattern, std::vector& res) { String filtersString; - if(parseOption(argc, argv, pattern, filtersString)) { - // tokenize with "," as a separator - // cppcheck-suppress strtokCalled - char* pch = std::strtok(filtersString.c_str(), ","); // modifies the string - while(pch != 0) { - if(strlen(pch)) - res.push_back(pch); - // uses the strtok() internal state to go to the next token - // cppcheck-suppress strtokCalled - pch = std::strtok(0, ","); + if(parseOption(argc, argv, pattern, &filtersString)) { + // tokenize with "," as a separator, unless escaped with backslash + std::ostringstream s; + auto flush = [&s, &res]() { + auto string = s.str(); + if(string.size() > 0) { + res.push_back(string.c_str()); + } + s.str(""); + }; + + bool seenBackslash = false; + const char* current = filtersString.c_str(); + const char* end = current + strlen(current); + while(current != end) { + char character = *current++; + if(seenBackslash) { + seenBackslash = false; + if(character == ',' || character == '\\') { + s.put(character); + continue; + } + s.put('\\'); + } + if(character == '\\') { + seenBackslash = true; + } else if(character == ',') { + flush(); + } else { + s.put(character); + } + } + + if(seenBackslash) { + s.put('\\'); } + flush(); return true; } return false; @@ -4915,275 +6482,181 @@ namespace detail bool parseIntOption(int argc, const char* const* argv, const char* pattern, optionType type, int& res) { String parsedValue; - if(!parseOption(argc, argv, pattern, parsedValue)) + if(!parseOption(argc, argv, pattern, &parsedValue)) return false; - if(type == 0) { + if(type) { + // integer + // TODO: change this to use std::stoi or something else! currently it uses undefined behavior - assumes '0' on failed parse... + int theInt = std::atoi(parsedValue.c_str()); + if (theInt != 0) { + res = theInt; //!OCLINT parameter reassignment + return true; + } + } else { // boolean - const char positive[][5] = {"1", "true", "on", "yes"}; // 5 - strlen("true") + 1 - const char negative[][6] = {"0", "false", "off", "no"}; // 6 - strlen("false") + 1 + const char positive[][5] = { "1", "true", "on", "yes" }; // 5 - strlen("true") + 1 + const char negative[][6] = { "0", "false", "off", "no" }; // 6 - strlen("false") + 1 // if the value matches any of the positive/negative possibilities - for(unsigned i = 0; i < 4; i++) { - if(parsedValue.compare(positive[i], true) == 0) { + for (unsigned i = 0; i < 4; i++) { + if (parsedValue.compare(positive[i], true) == 0) { res = 1; //!OCLINT parameter reassignment return true; } - if(parsedValue.compare(negative[i], true) == 0) { + if (parsedValue.compare(negative[i], true) == 0) { res = 0; //!OCLINT parameter reassignment return true; } } - } else { - // integer - int theInt = std::atoi(parsedValue.c_str()); // NOLINT - if(theInt != 0) { - res = theInt; //!OCLINT parameter reassignment - return true; - } } return false; } - - void printVersion(std::ostream& s) { - if(contextState->no_version == false) - s << Color::Cyan << "[doctest] " << Color::None << "doctest version is \"" - << DOCTEST_VERSION_STR << "\"\n"; - } - - void printHelp(std::ostream& s) { - printVersion(s); - // clang-format off - s << Color::Cyan << "[doctest]\n" << Color::None; - s << Color::Cyan << "[doctest] " << Color::None; - s << "boolean values: \"1/on/yes/true\" or \"0/off/no/false\"\n"; - s << Color::Cyan << "[doctest] " << Color::None; - s << "filter values: \"str1,str2,str3\" (comma separated strings)\n"; - s << Color::Cyan << "[doctest]\n" << Color::None; - s << Color::Cyan << "[doctest] " << Color::None; - s << "filters use wildcards for matching strings\n"; - s << Color::Cyan << "[doctest] " << Color::None; - s << "something passes a filter if any of the strings in a filter matches\n"; - s << Color::Cyan << "[doctest]\n" << Color::None; - s << Color::Cyan << "[doctest] " << Color::None; - s << "ALL FLAGS, OPTIONS AND FILTERS ALSO AVAILABLE WITH A \"dt-\" PREFIX!!!\n"; - s << Color::Cyan << "[doctest]\n" << Color::None; - s << Color::Cyan << "[doctest] " << Color::None; - s << "Query flags - the program quits after them. Available:\n\n"; - s << " -?, --help, -h prints this message\n"; - s << " -v, --version prints the version\n"; - s << " -c, --count prints the number of matching tests\n"; - s << " -ltc, --list-test-cases lists all matching tests by name\n"; - s << " -lts, --list-test-suites lists all matching test suites\n\n"; - // ================================================================================== << 79 - s << Color::Cyan << "[doctest] " << Color::None; - s << "The available / options/filters are:\n\n"; - s << " -tc, --test-case= filters tests by their name\n"; - s << " -tce, --test-case-exclude= filters OUT tests by their name\n"; - s << " -sf, --source-file= filters tests by their file\n"; - s << " -sfe, --source-file-exclude= filters OUT tests by their file\n"; - s << " -ts, --test-suite= filters tests by their test suite\n"; - s << " -tse, --test-suite-exclude= filters OUT tests by their test suite\n"; - s << " -sc, --subcase= filters subcases by their name\n"; - s << " -sce, --subcase-exclude= filters OUT subcases by their name\n"; - s << " -ob, --order-by= how the tests should be ordered\n"; - s << " - by [file/suite/name/rand]\n"; - s << " -rs, --rand-seed= seed for random ordering\n"; - s << " -f, --first= the first test passing the filters to\n"; - s << " execute - for range-based execution\n"; - s << " -l, --last= the last test passing the filters to\n"; - s << " execute - for range-based execution\n"; - s << " -aa, --abort-after= stop after failed assertions\n"; - s << " -scfl,--subcase-filter-levels= apply filters for the first levels\n"; - s << Color::Cyan << "\n[doctest] " << Color::None; - s << "Bool options - can be used like flags and true is assumed. Available:\n\n"; - s << " -s, --success= include successful assertions in output\n"; - s << " -cs, --case-sensitive= filters being treated as case sensitive\n"; - s << " -e, --exit= exits after the tests finish\n"; - s << " -d, --duration= prints the time duration of each test\n"; - s << " -nt, --no-throw= skips exceptions-related assert checks\n"; - s << " -ne, --no-exitcode= returns (or exits) always with success\n"; - s << " -nr, --no-run= skips all runtime doctest operations\n"; - s << " -nv, --no-version= omit the framework version in the output\n"; - s << " -nc, --no-colors= disables colors in output\n"; - s << " -fc, --force-colors= use colors even when not in a tty\n"; - s << " -nb, --no-breaks= disables breakpoints in debuggers\n"; - s << " -ns, --no-skip= don't skip test cases marked as skip\n"; - s << " -gfl, --gnu-file-line= :n: vs (n): for line numbers in output\n"; - s << " -npf, --no-path-filenames= only filenames and no paths in output\n"; - s << " -nln, --no-line-numbers= 0 instead of real line numbers in output\n"; - // ================================================================================== << 79 - // clang-format on - - s << Color::Cyan << "\n[doctest] " << Color::None; - s << "for more information visit the project documentation\n\n"; - } - - void printSummary(std::ostream& s) { - const ContextState* p = contextState; - - separator_to_stream(s); - - if(p->count || p->list_test_cases) { - s << Color::Cyan << "[doctest] " << Color::None - << "unskipped test cases passing the current filters: " << p->numTestsPassingFilters - << "\n"; - } else if(p->list_test_suites) { - s << Color::Cyan << "[doctest] " << Color::None - << "unskipped test cases passing the current filters: " << p->numTestsPassingFilters - << "\n"; - s << Color::Cyan << "[doctest] " << Color::None - << "test suites with unskipped test cases passing the current filters: " - << p->numTestSuitesPassingFilters << "\n"; - } else { - const bool anythingFailed = p->numFailed > 0 || p->numFailedAssertions > 0; - s << Color::Cyan << "[doctest] " << Color::None << "test cases: " << std::setw(6) - << p->numTestsPassingFilters << " | " - << ((p->numTestsPassingFilters == 0 || anythingFailed) ? Color::None : Color::Green) - << std::setw(6) << p->numTestsPassingFilters - p->numFailed << " passed" - << Color::None << " | " << (p->numFailed > 0 ? Color::Red : Color::None) - << std::setw(6) << p->numFailed << " failed" << Color::None << " | "; - if(p->no_skipped_summary == false) { - const int numSkipped = static_cast(getRegisteredTests().size()) - - p->numTestsPassingFilters; - s << (numSkipped == 0 ? Color::None : Color::Yellow) << std::setw(6) << numSkipped - << " skipped" << Color::None; - } - s << "\n"; - s << Color::Cyan << "[doctest] " << Color::None << "assertions: " << std::setw(6) - << p->numAssertions << " | " - << ((p->numAssertions == 0 || anythingFailed) ? Color::None : Color::Green) - << std::setw(6) << (p->numAssertions - p->numFailedAssertions) << " passed" - << Color::None << " | " << (p->numFailedAssertions > 0 ? Color::Red : Color::None) - << std::setw(6) << p->numFailedAssertions << " failed" << Color::None << " |\n"; - s << Color::Cyan << "[doctest] " << Color::None - << "Status: " << (p->numFailed > 0 ? Color::Red : Color::Green) - << ((p->numFailed > 0) ? "FAILURE!\n" : "SUCCESS!\n"); - } - - // remove any coloring - s << Color::None; - } -} // namespace detail - -bool isRunningInTest() { return detail::contextState != 0; } +} // namespace Context::Context(int argc, const char* const* argv) : p(new detail::ContextState) { parseArgs(argc, argv, true); + if(argc) + p->binary_name = argv[0]; } -Context::~Context() { delete p; } +Context::~Context() { + if(g_cs == p) + g_cs = nullptr; + delete p; +} -void Context::applyCommandLine(int argc, const char* const* argv) { parseArgs(argc, argv); } +void Context::applyCommandLine(int argc, const char* const* argv) { + parseArgs(argc, argv); + if(argc) + p->binary_name = argv[0]; +} // parses args void Context::parseArgs(int argc, const char* const* argv, bool withDefaults) { using namespace detail; // clang-format off - parseCommaSepArgs(argc, argv, "dt-source-file=", p->filters[0]); - parseCommaSepArgs(argc, argv, "dt-sf=", p->filters[0]); - parseCommaSepArgs(argc, argv, "dt-source-file-exclude=",p->filters[1]); - parseCommaSepArgs(argc, argv, "dt-sfe=", p->filters[1]); - parseCommaSepArgs(argc, argv, "dt-test-suite=", p->filters[2]); - parseCommaSepArgs(argc, argv, "dt-ts=", p->filters[2]); - parseCommaSepArgs(argc, argv, "dt-test-suite-exclude=", p->filters[3]); - parseCommaSepArgs(argc, argv, "dt-tse=", p->filters[3]); - parseCommaSepArgs(argc, argv, "dt-test-case=", p->filters[4]); - parseCommaSepArgs(argc, argv, "dt-tc=", p->filters[4]); - parseCommaSepArgs(argc, argv, "dt-test-case-exclude=", p->filters[5]); - parseCommaSepArgs(argc, argv, "dt-tce=", p->filters[5]); - parseCommaSepArgs(argc, argv, "dt-subcase=", p->filters[6]); - parseCommaSepArgs(argc, argv, "dt-sc=", p->filters[6]); - parseCommaSepArgs(argc, argv, "dt-subcase-exclude=", p->filters[7]); - parseCommaSepArgs(argc, argv, "dt-sce=", p->filters[7]); + parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "source-file=", p->filters[0]); + parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "sf=", p->filters[0]); + parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "source-file-exclude=",p->filters[1]); + parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "sfe=", p->filters[1]); + parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "test-suite=", p->filters[2]); + parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "ts=", p->filters[2]); + parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "test-suite-exclude=", p->filters[3]); + parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "tse=", p->filters[3]); + parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "test-case=", p->filters[4]); + parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "tc=", p->filters[4]); + parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "test-case-exclude=", p->filters[5]); + parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "tce=", p->filters[5]); + parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "subcase=", p->filters[6]); + parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "sc=", p->filters[6]); + parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "subcase-exclude=", p->filters[7]); + parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "sce=", p->filters[7]); + parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "reporters=", p->filters[8]); + parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "r=", p->filters[8]); // clang-format on int intRes = 0; String strRes; #define DOCTEST_PARSE_AS_BOOL_OR_FLAG(name, sname, var, default) \ - if(parseIntOption(argc, argv, name "=", option_bool, intRes) || \ - parseIntOption(argc, argv, sname "=", option_bool, intRes)) \ - p->var = !!intRes; \ - else if(parseFlag(argc, argv, name) || parseFlag(argc, argv, sname)) \ + if(parseIntOption(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX name "=", option_bool, intRes) || \ + parseIntOption(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX sname "=", option_bool, intRes)) \ + p->var = static_cast(intRes); \ + else if(parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX name) || \ + parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX sname)) \ p->var = true; \ else if(withDefaults) \ p->var = default #define DOCTEST_PARSE_INT_OPTION(name, sname, var, default) \ - if(parseIntOption(argc, argv, name "=", option_int, intRes) || \ - parseIntOption(argc, argv, sname "=", option_int, intRes)) \ + if(parseIntOption(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX name "=", option_int, intRes) || \ + parseIntOption(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX sname "=", option_int, intRes)) \ p->var = intRes; \ else if(withDefaults) \ p->var = default #define DOCTEST_PARSE_STR_OPTION(name, sname, var, default) \ - if(parseOption(argc, argv, name "=", strRes, default) || \ - parseOption(argc, argv, sname "=", strRes, default) || withDefaults) \ + if(parseOption(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX name "=", &strRes, default) || \ + parseOption(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX sname "=", &strRes, default) || \ + withDefaults) \ p->var = strRes // clang-format off - DOCTEST_PARSE_STR_OPTION("dt-order-by", "dt-ob", order_by, "file"); - DOCTEST_PARSE_INT_OPTION("dt-rand-seed", "dt-rs", rand_seed, 0); - - DOCTEST_PARSE_INT_OPTION("dt-first", "dt-f", first, 1); - DOCTEST_PARSE_INT_OPTION("dt-last", "dt-l", last, 0); - - DOCTEST_PARSE_INT_OPTION("dt-abort-after", "dt-aa", abort_after, 0); - DOCTEST_PARSE_INT_OPTION("dt-subcase-filter-levels", "dt-scfl", subcase_filter_levels, 2000000000); - - DOCTEST_PARSE_AS_BOOL_OR_FLAG("dt-success", "dt-s", success, false); - DOCTEST_PARSE_AS_BOOL_OR_FLAG("dt-case-sensitive", "dt-cs", case_sensitive, false); - DOCTEST_PARSE_AS_BOOL_OR_FLAG("dt-exit", "dt-e", exit, false); - DOCTEST_PARSE_AS_BOOL_OR_FLAG("dt-duration", "dt-d", duration, false); - DOCTEST_PARSE_AS_BOOL_OR_FLAG("dt-no-throw", "dt-nt", no_throw, false); - DOCTEST_PARSE_AS_BOOL_OR_FLAG("dt-no-exitcode", "dt-ne", no_exitcode, false); - DOCTEST_PARSE_AS_BOOL_OR_FLAG("dt-no-run", "dt-nr", no_run, false); - DOCTEST_PARSE_AS_BOOL_OR_FLAG("dt-no-version", "dt-nv", no_version, false); - DOCTEST_PARSE_AS_BOOL_OR_FLAG("dt-no-colors", "dt-nc", no_colors, false); - DOCTEST_PARSE_AS_BOOL_OR_FLAG("dt-force-colors", "dt-fc", force_colors, false); - DOCTEST_PARSE_AS_BOOL_OR_FLAG("dt-no-breaks", "dt-nb", no_breaks, false); - DOCTEST_PARSE_AS_BOOL_OR_FLAG("dt-no-skip", "dt-ns", no_skip, false); - DOCTEST_PARSE_AS_BOOL_OR_FLAG("dt-gnu-file-line", "dt-gfl", gnu_file_line, bool(DOCTEST_GCC) || bool(DOCTEST_CLANG)); - DOCTEST_PARSE_AS_BOOL_OR_FLAG("dt-no-path-filenames", "dt-npf", no_path_in_filenames, false); - DOCTEST_PARSE_AS_BOOL_OR_FLAG("dt-no-line-numbers", "dt-nln", no_line_numbers, false); - DOCTEST_PARSE_AS_BOOL_OR_FLAG("dt-no-skipped-summary", "dt-nss", no_skipped_summary, false); + DOCTEST_PARSE_STR_OPTION("out", "o", out, ""); + DOCTEST_PARSE_STR_OPTION("order-by", "ob", order_by, "file"); + DOCTEST_PARSE_INT_OPTION("rand-seed", "rs", rand_seed, 0); + + DOCTEST_PARSE_INT_OPTION("first", "f", first, 0); + DOCTEST_PARSE_INT_OPTION("last", "l", last, UINT_MAX); + + DOCTEST_PARSE_INT_OPTION("abort-after", "aa", abort_after, 0); + DOCTEST_PARSE_INT_OPTION("subcase-filter-levels", "scfl", subcase_filter_levels, INT_MAX); + + DOCTEST_PARSE_AS_BOOL_OR_FLAG("success", "s", success, false); + DOCTEST_PARSE_AS_BOOL_OR_FLAG("case-sensitive", "cs", case_sensitive, false); + DOCTEST_PARSE_AS_BOOL_OR_FLAG("exit", "e", exit, false); + DOCTEST_PARSE_AS_BOOL_OR_FLAG("duration", "d", duration, false); + DOCTEST_PARSE_AS_BOOL_OR_FLAG("minimal", "m", minimal, false); + DOCTEST_PARSE_AS_BOOL_OR_FLAG("quiet", "q", quiet, false); + DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-throw", "nt", no_throw, false); + DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-exitcode", "ne", no_exitcode, false); + DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-run", "nr", no_run, false); + DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-intro", "ni", no_intro, false); + DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-version", "nv", no_version, false); + DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-colors", "nc", no_colors, false); + DOCTEST_PARSE_AS_BOOL_OR_FLAG("force-colors", "fc", force_colors, false); + DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-breaks", "nb", no_breaks, false); + DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-skip", "ns", no_skip, false); + DOCTEST_PARSE_AS_BOOL_OR_FLAG("gnu-file-line", "gfl", gnu_file_line, !bool(DOCTEST_MSVC)); + DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-path-filenames", "npf", no_path_in_filenames, false); + DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-line-numbers", "nln", no_line_numbers, false); + DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-debug-output", "ndo", no_debug_output, false); + DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-skipped-summary", "nss", no_skipped_summary, false); + DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-time-in-output", "ntio", no_time_in_output, false); // clang-format on -#undef DOCTEST_PARSE_STR_OPTION -#undef DOCTEST_PARSE_INT_OPTION -#undef DOCTEST_PARSE_AS_BOOL_OR_FLAG - if(withDefaults) { p->help = false; p->version = false; p->count = false; p->list_test_cases = false; p->list_test_suites = false; + p->list_reporters = false; } - if(parseFlag(argc, argv, "dt-help") || parseFlag(argc, argv, "dt-h") || - parseFlag(argc, argv, "dt-?")) { + if(parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "help") || + parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "h") || + parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "?")) { p->help = true; p->exit = true; } - if(parseFlag(argc, argv, "dt-version") || parseFlag(argc, argv, "dt-v")) { + if(parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "version") || + parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "v")) { p->version = true; p->exit = true; } - if(parseFlag(argc, argv, "dt-count") || parseFlag(argc, argv, "dt-c")) { + if(parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "count") || + parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "c")) { p->count = true; p->exit = true; } - if(parseFlag(argc, argv, "dt-list-test-cases") || parseFlag(argc, argv, "dt-ltc")) { + if(parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "list-test-cases") || + parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "ltc")) { p->list_test_cases = true; p->exit = true; } - if(parseFlag(argc, argv, "dt-list-test-suites") || parseFlag(argc, argv, "dt-lts")) { + if(parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "list-test-suites") || + parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "lts")) { p->list_test_suites = true; p->exit = true; } + if(parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "list-reporters") || + parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "lr")) { + p->list_reporters = true; + p->exit = true; + } } // allows the user to add procedurally to the filters from the command line @@ -5191,114 +6664,210 @@ void Context::addFilter(const char* filter, const char* value) { setOption(filte // allows the user to clear all filters from the command line void Context::clearFilters() { - for(unsigned i = 0; i < p->filters.size(); ++i) - p->filters[i].clear(); + for(auto& curr : p->filters) + curr.clear(); +} + +// allows the user to override procedurally the bool options from the command line +void Context::setOption(const char* option, bool value) { + setOption(option, value ? "true" : "false"); } -// allows the user to override procedurally the int/bool options from the command line +// allows the user to override procedurally the int options from the command line void Context::setOption(const char* option, int value) { setOption(option, toString(value).c_str()); } // allows the user to override procedurally the string options from the command line void Context::setOption(const char* option, const char* value) { - String argv = String("-") + option + "=" + value; - const char* lvalue = argv.c_str(); + auto argv = String("-") + option + "=" + value; + auto lvalue = argv.c_str(); parseArgs(1, &lvalue); } // users should query this in their main() and exit the program if true bool Context::shouldExit() { return p->exit; } +void Context::setAsDefaultForAssertsOutOfTestCases() { g_cs = p; } + +void Context::setAssertHandler(detail::assert_handler ah) { p->ah = ah; } + +void Context::setCout(std::ostream* out) { p->cout = out; } + +static class DiscardOStream : public std::ostream +{ +private: + class : public std::streambuf + { + private: + // allowing some buffering decreases the amount of calls to overflow + char buf[1024]; + + protected: + std::streamsize xsputn(const char_type*, std::streamsize count) override { return count; } + + int_type overflow(int_type ch) override { + setp(std::begin(buf), std::end(buf)); + return traits_type::not_eof(ch); + } + } discardBuf; + +public: + DiscardOStream() + : std::ostream(&discardBuf) {} +} discardOut; + // the main function that does all the filtering and test running int Context::run() { using namespace detail; - Color::init(); + // save the old context state in case such was setup - for using asserts out of a testing context + auto old_cs = g_cs; + // this is the current contest + g_cs = p; + is_running_in_test = true; - contextState = p; + g_no_colors = p->no_colors; p->resetRunData(); - // handle version, help and no_run - if(p->no_run || p->version || p->help) { - if(p->version) - printVersion(std::cout); - if(p->help) - printHelp(std::cout); + std::fstream fstr; + if(p->cout == nullptr) { + if(p->quiet) { + p->cout = &discardOut; + } else if(p->out.size()) { + // to a file if specified + fstr.open(p->out.c_str(), std::fstream::out); + p->cout = &fstr; + } else { + // stdout by default + p->cout = &std::cout; + } + } + + FatalConditionHandler::allocateAltStackMem(); + + auto cleanup_and_return = [&]() { + FatalConditionHandler::freeAltStackMem(); + + if(fstr.is_open()) + fstr.close(); - contextState = 0; + // restore context + g_cs = old_cs; + is_running_in_test = false; + // we have to free the reporters which were allocated when the run started + for(auto& curr : p->reporters_currently_used) + delete curr; + p->reporters_currently_used.clear(); + + if(p->numTestCasesFailed && !p->no_exitcode) + return EXIT_FAILURE; return EXIT_SUCCESS; + }; + + // setup default reporter if none is given through the command line + if(p->filters[8].empty()) + p->filters[8].push_back("console"); + + // check to see if any of the registered reporters has been selected + for(auto& curr : getReporters()) { + if(matchesAny(curr.first.second.c_str(), p->filters[8], false, p->case_sensitive)) + p->reporters_currently_used.push_back(curr.second(*g_cs)); } - printVersion(std::cout); - std::cout << Color::Cyan << "[doctest] " << Color::None << "run with \"--help\" for options\n"; + // TODO: check if there is nothing in reporters_currently_used + + // prepend all listeners + for(auto& curr : getListeners()) + p->reporters_currently_used.insert(p->reporters_currently_used.begin(), curr.second(*g_cs)); + +#ifdef DOCTEST_PLATFORM_WINDOWS + if(isDebuggerActive() && p->no_debug_output == false) + p->reporters_currently_used.push_back(new DebugOutputWindowReporter(*g_cs)); +#endif // DOCTEST_PLATFORM_WINDOWS - unsigned i = 0; // counter used for loops - here for VC6 + // handle version, help and no_run + if(p->no_run || p->version || p->help || p->list_reporters) { + DOCTEST_ITERATE_THROUGH_REPORTERS(report_query, QueryData()); - std::set& registeredTests = getRegisteredTests(); + return cleanup_and_return(); + } std::vector testArray; - for(std::set::iterator it = registeredTests.begin(); it != registeredTests.end(); - ++it) - testArray.push_back(&(*it)); + for(auto& curr : getRegisteredTests()) + testArray.push_back(&curr); + p->numTestCases = testArray.size(); // sort the collected records if(!testArray.empty()) { if(p->order_by.compare("file", true) == 0) { - std::qsort(&testArray[0], testArray.size(), sizeof(TestCase*), fileOrderComparator); + std::sort(testArray.begin(), testArray.end(), fileOrderComparator); } else if(p->order_by.compare("suite", true) == 0) { - std::qsort(&testArray[0], testArray.size(), sizeof(TestCase*), suiteOrderComparator); + std::sort(testArray.begin(), testArray.end(), suiteOrderComparator); } else if(p->order_by.compare("name", true) == 0) { - std::qsort(&testArray[0], testArray.size(), sizeof(TestCase*), nameOrderComparator); + std::sort(testArray.begin(), testArray.end(), nameOrderComparator); } else if(p->order_by.compare("rand", true) == 0) { std::srand(p->rand_seed); // random_shuffle implementation - const TestCase** first = &testArray[0]; - for(i = testArray.size() - 1; i > 0; --i) { - int idxToSwap = std::rand() % (i + 1); // NOLINT + const auto first = &testArray[0]; + for(size_t i = testArray.size() - 1; i > 0; --i) { + int idxToSwap = std::rand() % (i + 1); - const TestCase* temp = first[i]; + const auto temp = first[i]; first[i] = first[idxToSwap]; first[idxToSwap] = temp; } + } else if(p->order_by.compare("none", true) == 0) { + // means no sorting - beneficial for death tests which call into the executable + // with a specific test case in mind - we don't want to slow down the startup times } } - if(p->list_test_cases) { - std::cout << Color::Cyan << "[doctest] " << Color::None << "listing all test case names\n"; - separator_to_stream(std::cout); - } + std::set testSuitesPassingFilt; - std::set testSuitesPassingFilters; - if(p->list_test_suites) { - std::cout << Color::Cyan << "[doctest] " << Color::None << "listing all test suites\n"; - separator_to_stream(std::cout); - } + bool query_mode = p->count || p->list_test_cases || p->list_test_suites; + std::vector queryResults; + + if(!query_mode) + DOCTEST_ITERATE_THROUGH_REPORTERS(test_run_start, DOCTEST_EMPTY); // invoke the registered functions if they match the filter criteria (or just count them) - for(i = 0; i < testArray.size(); i++) { - const TestCase& data = *testArray[i]; + for(auto& curr : testArray) { + const auto& tc = *curr; + + bool skip_me = false; + if(tc.m_skip && !p->no_skip) + skip_me = true; + + if(!matchesAny(tc.m_file.c_str(), p->filters[0], true, p->case_sensitive)) + skip_me = true; + if(matchesAny(tc.m_file.c_str(), p->filters[1], false, p->case_sensitive)) + skip_me = true; + if(!matchesAny(tc.m_test_suite, p->filters[2], true, p->case_sensitive)) + skip_me = true; + if(matchesAny(tc.m_test_suite, p->filters[3], false, p->case_sensitive)) + skip_me = true; + if(!matchesAny(tc.m_name, p->filters[4], true, p->case_sensitive)) + skip_me = true; + if(matchesAny(tc.m_name, p->filters[5], false, p->case_sensitive)) + skip_me = true; + + if(!skip_me) + p->numTestCasesPassingFilters++; - if(data.m_skip && !p->no_skip) - continue; + // skip the test if it is not in the execution range + if((p->last < p->numTestCasesPassingFilters && p->first <= p->last) || + (p->first > p->numTestCasesPassingFilters)) + skip_me = true; - if(!matchesAny(data.m_file, p->filters[0], 1, p->case_sensitive)) - continue; - if(matchesAny(data.m_file, p->filters[1], 0, p->case_sensitive)) + if(skip_me) { + if(!query_mode) + DOCTEST_ITERATE_THROUGH_REPORTERS(test_case_skipped, tc); continue; - if(!matchesAny(data.m_test_suite, p->filters[2], 1, p->case_sensitive)) - continue; - if(matchesAny(data.m_test_suite, p->filters[3], 0, p->case_sensitive)) - continue; - if(!matchesAny(data.m_name, p->filters[4], 1, p->case_sensitive)) - continue; - if(matchesAny(data.m_name, p->filters[5], 0, p->case_sensitive)) - continue; - - p->numTestsPassingFilters++; + } // do not execute the test if we are to only count the number of filter passing tests if(p->count) @@ -5306,159 +6875,145 @@ int Context::run() { // print the name of the test and don't execute it if(p->list_test_cases) { - std::cout << Color::None << data.m_name << "\n"; + queryResults.push_back(&tc); continue; } // print the name of the test suite if not done already and don't execute it if(p->list_test_suites) { - if((testSuitesPassingFilters.count(data.m_test_suite) == 0) && - data.m_test_suite[0] != '\0') { - std::cout << Color::None << data.m_test_suite << "\n"; - testSuitesPassingFilters.insert(data.m_test_suite); + if((testSuitesPassingFilt.count(tc.m_test_suite) == 0) && tc.m_test_suite[0] != '\0') { + queryResults.push_back(&tc); + testSuitesPassingFilt.insert(tc.m_test_suite); p->numTestSuitesPassingFilters++; } continue; } - // skip the test if it is not in the execution range - if((p->last < p->numTestsPassingFilters && p->first <= p->last) || - (p->first > p->numTestsPassingFilters)) - continue; - // execute the test if it passes all the filtering { - p->currentTest = &data; - - bool failed = false; - p->hasLoggedCurrentTestStart = false; - p->numFailedAssertionsForCurrentTestcase = 0; - p->subcasesPassed.clear(); - double duration = 0; - Timer timer; - timer.start(); - do { - // if the start has been logged from a previous iteration of this loop - if(p->hasLoggedCurrentTestStart) - logTestEnd(); - p->hasLoggedCurrentTestStart = false; + p->currentTest = &tc; + + p->failure_flags = TestCaseFailureReason::None; + p->seconds = 0; - // if logging successful tests - force the start log - if(p->success) - DOCTEST_LOG_START(std::cout); + // reset atomic counters + p->numAssertsFailedCurrentTest_atomic = 0; + p->numAssertsCurrentTest_atomic = 0; - // reset the assertion state - p->numAssertionsForCurrentTestcase = 0; - p->hasCurrentTestFailed = false; + p->fullyTraversedSubcases.clear(); + DOCTEST_ITERATE_THROUGH_REPORTERS(test_case_start, tc); + + p->timer.start(); + + bool run_test = true; + + do { // reset some of the fields for subcases (except for the set of fully passed ones) - p->subcasesHasSkipped = false; - p->subcasesCurrentLevel = 0; - p->subcasesEnteredLevels.clear(); + p->reachedLeaf = false; + // May not be empty if previous subcase exited via exception. + p->subcaseStack.clear(); + p->currentSubcaseDepth = 0; + + p->shouldLogCurrentException = true; // reset stuff for logging with INFO() - p->exceptionalContexts.clear(); + p->stringifiedContexts.clear(); -// execute the test #ifndef DOCTEST_CONFIG_NO_EXCEPTIONS try { #endif // DOCTEST_CONFIG_NO_EXCEPTIONS +// MSVC 2015 diagnoses fatalConditionHandler as unused (because reset() is a static method) +DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4101) // unreferenced local variable FatalConditionHandler fatalConditionHandler; // Handle signals - data.m_test(); + // execute the test + tc.m_test(); fatalConditionHandler.reset(); - if(contextState->hasCurrentTestFailed) - failed = true; +DOCTEST_MSVC_SUPPRESS_WARNING_POP #ifndef DOCTEST_CONFIG_NO_EXCEPTIONS - } catch(const TestFailureException&) { failed = true; } catch(...) { - DOCTEST_LOG_START(std::cout); - logTestException(*contextState->currentTest, translateActiveException(), false); - failed = true; + } catch(const TestFailureException&) { + p->failure_flags |= TestCaseFailureReason::AssertFailure; + } catch(...) { + DOCTEST_ITERATE_THROUGH_REPORTERS(test_case_exception, + {translateActiveException(), false}); + p->failure_flags |= TestCaseFailureReason::Exception; } #endif // DOCTEST_CONFIG_NO_EXCEPTIONS - p->numAssertions += p->numAssertionsForCurrentTestcase; - - // exit this loop if enough assertions have failed - if(p->abort_after > 0 && p->numFailedAssertions >= p->abort_after) { - p->subcasesHasSkipped = false; - std::cout << Color::Red << "Aborting - too many failed asserts!\n"; + // exit this loop if enough assertions have failed - even if there are more subcases + if(p->abort_after > 0 && + p->numAssertsFailed + p->numAssertsFailedCurrentTest_atomic >= p->abort_after) { + run_test = false; + p->failure_flags |= TestCaseFailureReason::TooManyFailedAsserts; } - } while(p->subcasesHasSkipped == true); - - duration = timer.getElapsedSeconds(); + if(!p->nextSubcaseStack.empty() && run_test) + DOCTEST_ITERATE_THROUGH_REPORTERS(test_case_reenter, tc); + if(p->nextSubcaseStack.empty()) + run_test = false; + } while(run_test); - if(Approx(p->currentTest->m_timeout).epsilon(DBL_EPSILON) != 0 && - Approx(duration).epsilon(DBL_EPSILON) > p->currentTest->m_timeout) { - failed = true; - DOCTEST_LOG_START(std::cout); - std::cout << Color::Red << "Test case exceeded time limit of " - << std::setprecision(6) << std::fixed << p->currentTest->m_timeout - << "!\n"; - } - - if(p->duration) - std::cout << Color::None << std::setprecision(6) << std::fixed << duration - << " s: " << p->currentTest->m_name << "\n"; - - if(data.m_should_fail) { - DOCTEST_LOG_START(std::cout); - if(failed) - std::cout << Color::Yellow - << "Failed as expected so marking it as not failed\n"; - else - std::cout << Color::Red - << "Should have failed but didn't! Marking it as failed!\n"; - failed = !failed; - } else if(failed && data.m_may_fail) { - DOCTEST_LOG_START(std::cout); - failed = false; - std::cout << Color::Yellow << "Allowed to fail so marking it as not failed\n"; - } else if(data.m_expected_failures > 0) { - DOCTEST_LOG_START(std::cout); - if(p->numFailedAssertionsForCurrentTestcase == data.m_expected_failures) { - failed = false; - std::cout << Color::Yellow << "Failed exactly " << data.m_expected_failures - << " times as expected so marking it as not failed!\n"; - } else { - failed = true; - std::cout << Color::Red << "Didn't fail exactly " << data.m_expected_failures - << " times so marking it as failed!\n"; - } - } - std::cout << Color::None; + p->finalizeTestCaseData(); - if(p->hasLoggedCurrentTestStart) - logTestEnd(); + DOCTEST_ITERATE_THROUGH_REPORTERS(test_case_end, *g_cs); - if(failed) // if any subcase has failed - the whole test case has failed - p->numFailed++; + p->currentTest = nullptr; // stop executing tests if enough assertions have failed - if(p->abort_after > 0 && p->numFailedAssertions >= p->abort_after) + if(p->abort_after > 0 && p->numAssertsFailed >= p->abort_after) break; } } - printSummary(std::cout); + if(!query_mode) { + DOCTEST_ITERATE_THROUGH_REPORTERS(test_run_end, *g_cs); + } else { + QueryData qdata; + qdata.run_stats = g_cs; + qdata.data = queryResults.data(); + qdata.num_data = unsigned(queryResults.size()); + DOCTEST_ITERATE_THROUGH_REPORTERS(report_query, qdata); + } + + return cleanup_and_return(); +} + +DOCTEST_DEFINE_INTERFACE(IReporter) - contextState = 0; +int IReporter::get_num_active_contexts() { return detail::g_infoContexts.size(); } +const IContextScope* const* IReporter::get_active_contexts() { + return get_num_active_contexts() ? &detail::g_infoContexts[0] : nullptr; +} - if(p->numFailed && !p->no_exitcode) - return EXIT_FAILURE; - return EXIT_SUCCESS; +int IReporter::get_num_stringified_contexts() { return detail::g_cs->stringifiedContexts.size(); } +const String* IReporter::get_stringified_contexts() { + return get_num_stringified_contexts() ? &detail::g_cs->stringifiedContexts[0] : nullptr; } + +namespace detail { + void registerReporterImpl(const char* name, int priority, reporterCreatorFunc c, bool isReporter) { + if(isReporter) + getReporters().insert(reporterMap::value_type(reporterMap::key_type(priority, name), c)); + else + getListeners().insert(reporterMap::value_type(reporterMap::key_type(priority, name), c)); + } +} // namespace detail + } // namespace doctest #endif // DOCTEST_CONFIG_DISABLE #ifdef DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN +DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4007) // 'function' : must be 'attribute' - see issue #182 int main(int argc, char** argv) { return doctest::Context(argc, argv).run(); } +DOCTEST_MSVC_SUPPRESS_WARNING_POP #endif // DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN DOCTEST_CLANG_SUPPRESS_WARNING_POP DOCTEST_MSVC_SUPPRESS_WARNING_POP DOCTEST_GCC_SUPPRESS_WARNING_POP +DOCTEST_SUPPRESS_COMMON_WARNINGS_POP + #endif // DOCTEST_LIBRARY_IMPLEMENTATION #endif // DOCTEST_CONFIG_IMPLEMENT From 83272eb965a799743497dc63d0900498322cc281 Mon Sep 17 00:00:00 2001 From: Vissarion Fisikopoulos Date: Sat, 29 Oct 2022 20:19:19 +0100 Subject: [PATCH 07/20] Disactivate g++13 and clang++-15 from Ubuntu 22 actions until they become available. --- .github/workflows/cmake-clang.yml | 2 +- .github/workflows/cmake-gcc.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/cmake-clang.yml b/.github/workflows/cmake-clang.yml index 6a4a8518c..5386c3963 100644 --- a/.github/workflows/cmake-clang.yml +++ b/.github/workflows/cmake-clang.yml @@ -20,7 +20,7 @@ jobs: - {os: ubuntu-22.04, compiler_pkg: clang-12, compiler: clang++-12} - {os: ubuntu-22.04, compiler_pkg: clang-13, compiler: clang++-13} - {os: ubuntu-22.04, compiler_pkg: clang-14, compiler: clang++-14} - - {os: ubuntu-22.04, compiler_pkg: clang-15, compiler: clang++-15} + #- {os: ubuntu-22.04, compiler_pkg: clang-15, compiler: clang++-15} - {os: ubuntu-20.04, compiler_pkg: clang-8, compiler: clang++-8} - {os: ubuntu-20.04, compiler_pkg: clang-9, compiler: clang++-9} - {os: ubuntu-20.04, compiler_pkg: clang-10, compiler: clang++-10} diff --git a/.github/workflows/cmake-gcc.yml b/.github/workflows/cmake-gcc.yml index 704df9250..e42805492 100644 --- a/.github/workflows/cmake-gcc.yml +++ b/.github/workflows/cmake-gcc.yml @@ -20,7 +20,7 @@ jobs: - {os: ubuntu-22.04, compiler: g++-10} - {os: ubuntu-22.04, compiler: g++-11} - {os: ubuntu-22.04, compiler: g++-12} - - {os: ubuntu-22.04, compiler: g++-13} + #- {os: ubuntu-22.04, compiler: g++-13} - {os: ubuntu-20.04, compiler: g++-7} - {os: ubuntu-20.04, compiler: g++-8} - {os: ubuntu-20.04, compiler: g++-9} From 16717d3690fbbae6b2927cc36c6107accab3e7fa Mon Sep 17 00:00:00 2001 From: Vissarion Fisikopoulos Date: Tue, 1 Nov 2022 10:08:40 +0200 Subject: [PATCH 08/20] Fix R actions. --- .github/workflows/R-CMD-check-macOS.yml | 8 ++++---- .github/workflows/R-CMD-check-ubuntu.yml | 6 +++--- .github/workflows/R-CMD-check-windows.yml | 8 ++++---- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/.github/workflows/R-CMD-check-macOS.yml b/.github/workflows/R-CMD-check-macOS.yml index 4645e0a09..23ac6d616 100644 --- a/.github/workflows/R-CMD-check-macOS.yml +++ b/.github/workflows/R-CMD-check-macOS.yml @@ -30,13 +30,13 @@ jobs: GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - - uses: r-lib/actions/setup-r@master + - uses: r-lib/actions/setup-r@v2 with: r-version: ${{ matrix.config.r }} - - uses: r-lib/actions/setup-pandoc@master + - uses: r-lib/actions/setup-pandoc@v2 - name: Install dependencies run: Rscript -e "install.packages(c('devtools', dependencies=TRUE))" -e "install.packages(c('rcmdcheck', 'devtools', 'Rcpp', 'RcppEigen', 'BH', 'testthat', 'downloader', 'xfun'))"; @@ -51,7 +51,7 @@ jobs: - name: Upload check results if: failure() - uses: actions/upload-artifact@master + uses: actions/upload-artifact@v2 with: name: ${{ runner.os }}-r${{ matrix.config.r }}-results path: check diff --git a/.github/workflows/R-CMD-check-ubuntu.yml b/.github/workflows/R-CMD-check-ubuntu.yml index dc066b396..645396120 100644 --- a/.github/workflows/R-CMD-check-ubuntu.yml +++ b/.github/workflows/R-CMD-check-ubuntu.yml @@ -31,7 +31,7 @@ jobs: GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - run: sudo apt-get update || true; sudo apt install build-essential libcurl4-gnutls-dev libxml2-dev libssl-dev libgit2-dev libfontconfig1-dev libharfbuzz-dev libfribidi-dev; @@ -39,7 +39,7 @@ jobs: with: r-version: ${{ matrix.config.r }} - - uses: r-lib/actions/setup-pandoc@master + - uses: r-lib/actions/setup-pandoc@v2 - name: Install dependencies run: Rscript -e "install.packages(c('testthat', 'pkgload', 'rcmdcheck', 'devtools', 'Rcpp', 'RcppEigen', 'BH', 'downloader', 'xfun', dependencies=TRUE))"; @@ -54,7 +54,7 @@ jobs: - name: Upload check results if: failure() - uses: actions/upload-artifact@master + uses: actions/upload-artifact@v2 with: name: ${{ runner.os }}-r${{ matrix.config.r }}-results path: check diff --git a/.github/workflows/R-CMD-check-windows.yml b/.github/workflows/R-CMD-check-windows.yml index 510da501d..ad56a7170 100644 --- a/.github/workflows/R-CMD-check-windows.yml +++ b/.github/workflows/R-CMD-check-windows.yml @@ -29,13 +29,13 @@ jobs: GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - - uses: r-lib/actions/setup-r@master + - uses: r-lib/actions/setup-r@v2 with: r-version: ${{ matrix.config.r }} - - uses: r-lib/actions/setup-pandoc@master + - uses: r-lib/actions/setup-pandoc@v2 - name: Install dependencies run: Rscript -e "install.packages(c('devtools', dependencies=TRUE))" -e "install.packages(c('rcmdcheck', 'devtools', 'Rcpp', 'RcppEigen', 'BH', 'testthat', 'downloader', 'xfun'))" @@ -50,7 +50,7 @@ jobs: - name: Upload check results if: failure() - uses: actions/upload-artifact@master + uses: actions/upload-artifact@v2 with: name: ${{ runner.os }}-r${{ matrix.config.r }}-results path: check From b94484eb52a57738cae5413635f74b46faf10df2 Mon Sep 17 00:00:00 2001 From: Vissarion Fisikopoulos Date: Tue, 1 Nov 2022 10:43:21 +0200 Subject: [PATCH 09/20] Fix link to lp_solve --- test/LpSolve.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/LpSolve.cmake b/test/LpSolve.cmake index 7cfee4ec9..55dc901b9 100644 --- a/test/LpSolve.cmake +++ b/test/LpSolve.cmake @@ -5,7 +5,7 @@ function(GetLPSolve) include(FetchContent) FetchContent_Declare( lpsolve - URL https://cran.r-project.org/src/contrib/lpSolve_5.6.15.tar.gz + URL https://cran.r-project.org/src/contrib/Archive/lpSolve/lpSolve_5.6.15.tar.gz URL_HASH MD5=3b8d780f703e0da2e4863939add164bc ) From 774abdb3681857bbd4033a155fb18ae455ae16b7 Mon Sep 17 00:00:00 2001 From: iakoviid <44919975+iakoviid@users.noreply.github.com> Date: Wed, 2 Nov 2022 11:09:45 +0200 Subject: [PATCH 10/20] Constrained Riemannian Hamiltonian Monte Carlo Walk (#239) --- examples/crhmc_prepare/data/cube10.ine | 26 - examples/crhmc_sampling/.gitignore | 3 + examples/crhmc_sampling/CMakeLists.txt | 128 +++ examples/crhmc_sampling/README.md | 21 + examples/crhmc_sampling/crhmc_sampling.cpp | 153 +++ examples/logconcave/README.md | 10 +- .../plot_ode.py | 0 .../plot_samples.py} | 19 +- include/ode_solvers/implicit_midpoint.hpp | 180 +++ include/ode_solvers/ode_solvers.hpp | 1 + include/ode_solvers/oracle_functors.hpp | 7 +- include/preprocess/crhmc/crhmc_problem.h | 4 +- include/preprocess/crhmc/lewis_center.h | 2 +- include/preprocess/crhmc/opts.h | 3 +- .../crhmc/two_sided_barrier.h} | 27 +- .../crhmc/weighted_two_sided_barrier.h | 146 +++ .../crhmc/additional_units/auto_tuner.hpp | 65 ++ .../additional_units/dynamic_regularizer.hpp | 56 + .../additional_units/dynamic_step_size.hpp | 103 ++ .../crhmc/additional_units/dynamic_weight.hpp | 70 ++ include/random_walks/crhmc/crhmc_walk.hpp | 230 ++++ include/random_walks/crhmc/hamiltonian.hpp | 233 ++++ include/random_walks/random_walks.hpp | 2 +- test/CMakeLists.txt | 30 +- test/benchmarks_crhmc_sampling.cpp | 387 +++++++ test/crhmc_sampling_test.cpp | 506 +++++++++ test/ode_solvers_test.cpp | 709 ++++++------ test/test_norm_hypercube.txt | 1000 +++++++++++++++++ 28 files changed, 3726 insertions(+), 395 deletions(-) delete mode 100644 examples/crhmc_prepare/data/cube10.ine create mode 100644 examples/crhmc_sampling/.gitignore create mode 100644 examples/crhmc_sampling/CMakeLists.txt create mode 100644 examples/crhmc_sampling/README.md create mode 100644 examples/crhmc_sampling/crhmc_sampling.cpp rename examples/{logconcave => python_utilities}/plot_ode.py (100%) rename examples/{logconcave/plot_hmc.py => python_utilities/plot_samples.py} (86%) create mode 100644 include/ode_solvers/implicit_midpoint.hpp rename include/{sos/barriers/TwoSidedBarrier.h => preprocess/crhmc/two_sided_barrier.h} (85%) create mode 100644 include/preprocess/crhmc/weighted_two_sided_barrier.h create mode 100644 include/random_walks/crhmc/additional_units/auto_tuner.hpp create mode 100644 include/random_walks/crhmc/additional_units/dynamic_regularizer.hpp create mode 100644 include/random_walks/crhmc/additional_units/dynamic_step_size.hpp create mode 100644 include/random_walks/crhmc/additional_units/dynamic_weight.hpp create mode 100644 include/random_walks/crhmc/crhmc_walk.hpp create mode 100644 include/random_walks/crhmc/hamiltonian.hpp create mode 100644 test/benchmarks_crhmc_sampling.cpp create mode 100644 test/crhmc_sampling_test.cpp create mode 100644 test/test_norm_hypercube.txt diff --git a/examples/crhmc_prepare/data/cube10.ine b/examples/crhmc_prepare/data/cube10.ine deleted file mode 100644 index a750ed5b4..000000000 --- a/examples/crhmc_prepare/data/cube10.ine +++ /dev/null @@ -1,26 +0,0 @@ -cube10.ine -H-representation -begin - 20 11 real - 1 1 0 0 0 0 0 0 0 0 0 - 1 0 1 0 0 0 0 0 0 0 0 - 1 0 0 1 0 0 0 0 0 0 0 - 1 0 0 0 1 0 0 0 0 0 0 - 1 0 0 0 0 1 0 0 0 0 0 - 1 0 0 0 0 0 1 0 0 0 0 - 1 0 0 0 0 0 0 1 0 0 0 - 1 0 0 0 0 0 0 0 1 0 0 - 1 0 0 0 0 0 0 0 0 1 0 - 1 0 0 0 0 0 0 0 0 0 1 - 1 -1 0 0 0 0 0 0 0 0 0 - 1 0 -1 0 0 0 0 0 0 0 0 - 1 0 0 -1 0 0 0 0 0 0 0 - 1 0 0 0 -1 0 0 0 0 0 0 - 1 0 0 0 0 -1 0 0 0 0 0 - 1 0 0 0 0 0 -1 0 0 0 0 - 1 0 0 0 0 0 0 -1 0 0 0 - 1 0 0 0 0 0 0 0 -1 0 0 - 1 0 0 0 0 0 0 0 0 -1 0 - 1 0 0 0 0 0 0 0 0 0 -1 -end -input_incidence diff --git a/examples/crhmc_sampling/.gitignore b/examples/crhmc_sampling/.gitignore new file mode 100644 index 000000000..5ba563ce6 --- /dev/null +++ b/examples/crhmc_sampling/.gitignore @@ -0,0 +1,3 @@ +crhmc_sampling +samples.txt +libQD_LIB.a diff --git a/examples/crhmc_sampling/CMakeLists.txt b/examples/crhmc_sampling/CMakeLists.txt new file mode 100644 index 000000000..bb206ea49 --- /dev/null +++ b/examples/crhmc_sampling/CMakeLists.txt @@ -0,0 +1,128 @@ +# VolEsti (volume computation and sampling library) +# Copyright (c) 2012-2021 Vissarion Fisikopoulos +# Copyright (c) 2018-2021 Apostolos Chalkis +# Contributed and/or modified by Ioannis Iakovidis +# Licensed under GNU LGPL.3, see LICENCE file + +project( VolEsti ) + + +CMAKE_MINIMUM_REQUIRED(VERSION 3.11) + +set(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS true) + +# Locate Intel MKL root (in case it is enabled) +if (APPLE) + set(MKLROOT /opt/intel/oneapi/mkl/latest) +elseif(UNIX) + #set(MKLROOT /opt/intel/oneapi/mkl/latest) + set(MKLROOT $ENV{HOME}/intel/mkl) +endif() + +if(COMMAND cmake_policy) + cmake_policy(SET CMP0003 NEW) +endif(COMMAND cmake_policy) + + +option(DISABLE_NLP_ORACLES "Disable non-linear oracles (used in collocation)" ON) +option(BUILTIN_EIGEN "Use eigen from ../../external" OFF) +option(USE_MKL "Use MKL library to build eigen" OFF) + + +if(DISABLE_NLP_ORACLES) + add_definitions(-DDISABLE_NLP_ORACLES) +else() + find_library(IFOPT NAMES libifopt_core.so PATHS /usr/local/lib) + find_library(IFOPT_IPOPT NAMES libifopt_ipopt.so PATHS /usr/local/lib) + find_library(GMP NAMES libgmp.so PATHS /usr/lib/x86_64-linux-gnu /usr/lib/i386-linux-gnu) + find_library(MPSOLVE NAMES libmps.so PATHS /usr/local/lib) + find_library(PTHREAD NAMES libpthread.so PATHS /usr/lib/x86_64-linux-gnu /usr/lib/i386-linux-gnu) + find_library(FFTW3 NAMES libfftw3.so.3 PATHS /usr/lib/x86_64-linux-gnu /usr/lib/i386-linux-gnu) + + if (NOT IFOPT) + + message(FATAL_ERROR "This program requires the ifopt library, and will not be compiled.") + + elseif (NOT GMP) + + message(FATAL_ERROR "This program requires the gmp library, and will not be compiled.") + + elseif (NOT MPSOLVE) + + message(FATAL_ERROR "This program requires the mpsolve library, and will not be compiled.") + + elseif (NOT FFTW3) + + message(FATAL_ERROR "This program requires the fftw3 library, and will not be compiled.") + + else() + message(STATUS "Library ifopt found: ${IFOPT}") + message(STATUS "Library gmp found: ${GMP}") + message(STATUS "Library mpsolve found: ${MPSOLVE}") + message(STATUS "Library fftw3 found:" ${FFTW3}) + + endif(NOT IFOPT) + +endif(DISABLE_NLP_ORACLES) + +include("../../external/cmake-files/Eigen.cmake") +GetEigen() + +include("../../external/cmake-files/Boost.cmake") +GetBoost() + +include("../../external/cmake-files/LPSolve.cmake") +GetLPSolve() + +include("../../external/cmake-files/QD.cmake") +GetQD() + +# Find lpsolve library +find_library(LP_SOLVE NAMES liblpsolve55.so PATHS /usr/lib/lp_solve) + +if (NOT LP_SOLVE) + message(FATAL_ERROR "This program requires the lp_solve library, and will not be compiled.") +else () + message(STATUS "Library lp_solve found: ${LP_SOLVE}") + + set(CMAKE_EXPORT_COMPILE_COMMANDS "ON") + + if (USE_MKL) + find_library(BLAS NAMES libblas.so libblas.dylib PATHS /usr/local/Cellar/lapack/3.9.1_1/lib /usr/lib/x86_64-linux-gnu /usr/lib/i386-linux-gnu /usr/local/Cellar/openblas/0.3.15_1/lib /usr/lib) + find_library(GFORTRAN NAME libgfortran.dylib PATHS /usr/local/Cellar/gcc/10.2.0_4/lib/gcc/10) + find_library(LAPACK NAME liblapack.dylib PATHS /usr/lib) + find_library(OPENMP NAME libiomp5.dylib PATHS /opt/intel/oneapi/compiler/2021.1.1/mac/compiler/lib) + + include_directories (BEFORE ${MKLROOT}/include) + set(PROJECT_LIBS ${BLAS_LIBRARIES} ${LAPACK_LIBRARIES} ${GFORTRAN_LIBRARIES}) + set(MKL_LINK "-L${MKLROOT}/lib -Wl,-rpath,${MKLROOT}/lib -lmkl_intel_ilp64 -lmkl_sequential -lmkl_core -lpthread -lm -ldl") + add_definitions(-DEIGEN_USE_MKL_ALL) + else() + set(MKL_LINK "") + endif(USE_MKL) + + include_directories (BEFORE ../../external) + include_directories (BEFORE ../../external/minimum_ellipsoid) + include_directories (BEFORE ../../include/) + + # for Eigen + if (${CMAKE_VERSION} VERSION_LESS "3.12.0") + add_compile_options(-D "EIGEN_NO_DEBUG") + else () + add_compile_definitions("EIGEN_NO_DEBUG") + endif () + + + add_definitions(${CMAKE_CXX_FLAGS} "-std=c++11") # enable C++11 standard + #add_definitions(${CMAKE_CXX_FLAGS} "-g") # enable debuger + set(ADDITIONAL_FLAGS "-march=native -DSIMD_LEN=0 -DTIME_KEEPING") + add_definitions(${CMAKE_CXX_FLAGS} "-O3 " ${ADDITIONAL_FLAGS}) # optimization of the compiler + #add_definitions(${CXX_COVERAGE_COMPILE_FLAGS} "-lgsl") + add_definitions(${CXX_COVERAGE_COMPILE_FLAGS} "-lm") + add_definitions(${CXX_COVERAGE_COMPILE_FLAGS} "-ldl") + add_definitions(${CXX_COVERAGE_COMPILE_FLAGS} "-DBOOST_NO_AUTO_PTR") + + add_executable (crhmc_sampling crhmc_sampling.cpp) + TARGET_LINK_LIBRARIES(crhmc_sampling ${QD_LIB} ${MKL_LINK} ${LP_SOLVE}) + +endif() diff --git a/examples/crhmc_sampling/README.md b/examples/crhmc_sampling/README.md new file mode 100644 index 000000000..38070b2d3 --- /dev/null +++ b/examples/crhmc_sampling/README.md @@ -0,0 +1,21 @@ +## Constrained Riemannian Hamiltonian Monte Carlo for Polytopes +This is an example that illustrates sampling from the random walk for the hypercube. + +References: +Yunbum Kook, Yin Tat Lee, Ruoqi Shen, Santosh S. Vempala. "Sampling with Riemannian Hamiltonian + Monte Carlo in a Constrained Space" +## Compilation +Build the example by running the following commands in this directory. + +```bash +cmake . -DLP_SOLVE=_PATH_TO_LIB_FILE +make +``` +You have to specify the path to liblpsolve55.so/dll/dylib. +For example: -DLP_SOLVE=/usr/lib/lpsolve/liblpsolve55.so + +## Running: +```bash + ./crhmc_sampling >samples.txt + python3 ../python_utilities/plot_samples.py +#include +#include +#include +#include +#include +#include + +#include "Eigen/Eigen" +#include "cartesian_geom/cartesian_kernel.h" +#include "diagnostics/multivariate_psrf.hpp" +#include "ode_solvers/ode_solvers.hpp" +#include "preprocess/crhmc/crhmc_input.h" +#include "preprocess/crhmc/crhmc_problem.h" +#include "random.hpp" +#include "random/normal_distribution.hpp" +#include "random/uniform_int.hpp" +#include "random/uniform_real_distribution.hpp" +#include "random_walks/random_walks.hpp" +#include "ode_solvers/oracle_functors.hpp" + +template +void run_main(int n_samples = 10000, int n_burns = -1, int dimension = 2, + int walk_length = 1, int burn_steps = 1) { + using Kernel = Cartesian; + using Point = typename Kernel::Point; + using MT = Eigen::Matrix; + using VT = Eigen::Matrix; + using RandomNumberGenerator = BoostRandomNumberGenerator; + using Func = GaussianFunctor::FunctionFunctor; + using Grad = GaussianFunctor::GradientFunctor; + using Hess = GaussianFunctor::HessianFunctor; + using func_params = GaussianFunctor::parameters; + using Input = crhmc_input; + using CrhmcProblem = crhmc_problem; + using Solver = ImplicitMidpointODESolver; + using Opts = opts; + using Hpolytope = HPolytope; + + func_params params = func_params(Point(dimension), 4, 1); + Func f(params); + Grad g(params); + Hess h(params); + if (n_burns == -1) { + n_burns = n_samples / 2; + } + RandomNumberGenerator rng(1); + unsigned int dim = dimension; + Opts options; + + CRHMCWalk::parameters crhmc_params(g, dim, options); + Input input = Input(dim, f, g, h); + input.lb = -VT::Ones(dim); + input.ub = VT::Ones(dim); + CrhmcProblem P = CrhmcProblem(input, options); + P.print(); + Point x0 = Point(P.center); + crhmc_params.eta = 0.2; + crhmc_params.momentum = 0.8; + CRHMCWalk::Walk + crhmc(P, x0, g, f, crhmc_params); + MT samples = MT(dim, n_samples - n_burns); +#ifdef TIME_KEEPING + std::chrono::time_point start, end; + start = std::chrono::high_resolution_clock::now(); +#endif +#ifdef TIME_KEEPING + std::chrono::time_point start_file, + end_file; + std::chrono::duration total_time_file = + std::chrono::duration::zero(); +#endif + int j = 0; + for (int i = 0; i < n_samples; i++) { + if (i % 1000 == 0) { + std::cerr << i << " out of " << n_samples << "\n"; + } + for (int k = 0; k < burn_steps; k++) { + crhmc.apply(rng, walk_length, true); + } +#ifdef TIME_KEEPING + start_file = std::chrono::high_resolution_clock::now(); +#endif + if (i >= n_burns) { + VT sample = crhmc.getPoint().getCoefficients(); + samples.col(j) = VT(sample); + j++; + } +#ifdef TIME_KEEPING + end_file = std::chrono::high_resolution_clock::now(); + total_time_file += end_file - start_file; +#endif + } + std::cerr << "\n"; +#ifdef TIME_KEEPING + end = std::chrono::high_resolution_clock::now(); + std::chrono::duration total_time = end - start; + std::cerr << "Total time: " << total_time.count() << "\n"; + crhmc.print_timing_information(); +#endif + + std::cerr << "Step size (final): " << crhmc.solver->eta << std::endl; + std::cerr << "Discard Ratio: " << crhmc.discard_ratio << std::endl; + std::cerr << "Average Acceptance Probability: " + << crhmc.average_acceptance_prob << std::endl; + std::cerr << "PSRF: " << multivariate_psrf(samples) << std::endl; +#ifdef TIME_KEEPING + start_file = std::chrono::high_resolution_clock::now(); +#endif + std::cerr << "Writing samples in a file \n"; + std::cout << samples.transpose() << std::endl; +#ifdef TIME_KEEPING + end_file = std::chrono::high_resolution_clock::now(); + total_time_file += end_file - start_file; + std::cerr << "Time for writing the file: " << total_time_file.count() << "\n"; +#endif +} + +int main(int argc, char *argv[]) { + std::cerr << "Example Usage: ./crhmc_sampling n_sample initial_burns " + "dimension ode_steps steps_bettween_samples\n"; + std::cerr << "Example Usage: ./crhmc_sampling 10000 5000 " + "2 1 1\n"; + if (argc == 1) + run_main(); + else if (argc == 2) + run_main(atoi(argv[1])); + else if (argc == 3) + run_main(atoi(argv[1]), atoi(argv[2])); + else if (argc == 4) + run_main(atoi(argv[1]), atoi(argv[2]), atoi(argv[3])); + else if (argc == 5) + run_main(atoi(argv[1]), atoi(argv[2]), atoi(argv[3]), + atoi(argv[4])); + return 0; +} diff --git a/examples/logconcave/README.md b/examples/logconcave/README.md index 47fffa259..e29631231 100644 --- a/examples/logconcave/README.md +++ b/examples/logconcave/README.md @@ -2,7 +2,7 @@ You have to install the latest mkl [MKL](https://www.intel.com/content/www/us/en/developer/tools/oneapi/onemkl-download.html) -For example, it is installed in the directory "/opt/intel/oneapi/mkl/2022.1.0". +For example, it is installed in the directory "/opt/intel/oneapi/mkl/2022.1.0". Change the environment variable: ```bash @@ -29,8 +29,8 @@ Now, you can the HMC and ODE examples and generate their outputs ``` For plotting the results there are two scripts - * `plot_hmc.py` for plotting the outputs of the HMC sampler - * `plot_ode.py` for plotting the outputs of the ODE solver + * `examples/python_utilities/plot_samples.py` for plotting the outputs of the HMC sampler + * `examples/python_utilities/plot_ode.py` for plotting the outputs of the ODE solver These scripts have requirements listed in `requirements.txt`. Install via ``` @@ -39,8 +39,8 @@ pip install -r requirements.txt Plot the results as ``` - python plot_hmc.py 4: + dims=2 + print('Due to the large number of dimensions you will get plots for only {} dimensions'.format(dims)) print('Plotting histograms of marginal densities') fig, ax2d = plt.subplots(ncols=dims, nrows=1, squeeze=False) axli = ax2d.flatten() plt.suptitle('{}: Marginals'.format(args.name)) - for i in range(1, 1 + dims): sns.histplot(data[:, i-1], bins=50, color="orange", ax=axli[i-1], stat='probability', kde=True) axli[i-1].set_xlabel('$x_{}$'.format(i)) @@ -65,7 +68,6 @@ axli = ax2d.flatten() plt.suptitle('{}: Samples'.format(args.name)) - for i in range(1, 1 + dims): axli[i-1].plot(data[:, i-1]) axli[i-1].set_xlabel('Number of samples (t)') @@ -73,7 +75,14 @@ if args.save: plt.savefig('{}_samples.png'.format(args.name)) - + if dims==2: + print('Printing 2 dimensional histogram') + fig2 = plt.figure() + plt.hist2d(data[:, 0], data[:, 1],100) + plt.xlabel('x') + plt.ylabel('y') + cbar = plt.colorbar() + cbar.ax.set_ylabel('Counts') if dims in [2, 3]: print('Plotting scatterplot') fig = plt.figure() diff --git a/include/ode_solvers/implicit_midpoint.hpp b/include/ode_solvers/implicit_midpoint.hpp new file mode 100644 index 000000000..71408e542 --- /dev/null +++ b/include/ode_solvers/implicit_midpoint.hpp @@ -0,0 +1,180 @@ +// VolEsti (volume computation and sampling library) + +// Copyright (c) 2012-2020 Vissarion Fisikopoulos +// Copyright (c) 2018-2020 Apostolos Chalkis +// Copyright (c) 2022-2022 Ioannis Iakovidis + +// Contributed and/or modified by Ioannis Iakovidis, as part of Google Summer of +// Code 2022 program. + +// Licensed under GNU LGPL.3, see LICENCE file + +// References +// Yunbum Kook, Yin Tat Lee, Ruoqi Shen, Santosh S. Vempala. "Sampling with +// Riemannian Hamiltonian +// Monte Carlo in a Constrained Space" + +#ifndef IMPLICIT_MIDPOINT_HPP +#define IMPLICIT_MIDPOINT_HPP +#include "preprocess/crhmc/opts.h" +#include "random_walks/crhmc/hamiltonian.hpp" +#ifdef TIME_KEEPING +#include +#endif + +template +inline std::vector operator+(const std::vector &v1, + const std::vector &v2) +{ + std::vector result(v1.size()); + for (int i = 0; i < v1.size(); i++) { + result[i] = v1[i] + v2[i]; + } + return result; +} +template +inline std::vector operator*(const std::vector &v, const Type alpha) +{ + std::vector result(v.size()); + for (int i = 0; i < v.size(); i++) { + result[i] = v[i] * alpha; + } + return result; +} +template +inline std::vector operator/(const std::vector &v, const Type alpha) +{ + return v * (1 / alpha); +} +template +inline std::vector operator-(const std::vector &v1, + const std::vector &v2) +{ + + return v1 + v2 * (-1.0); +} +template +struct ImplicitMidpointODESolver { + using VT = typename Polytope::VT; + using MT = typename Polytope::MT; + using pts = std::vector; + using hamiltonian = Hamiltonian; + using Opts = opts; + + unsigned int dim; + + NT eta; + int num_steps = 0; + NT t; + + // Contains the sub-states + pts xs; + pts xs_prev; + + // Function oracle + func F; + Polytope &P; + Opts &options; + VT nu; + + hamiltonian ham; + + bool done; +#ifdef TIME_KEEPING + std::chrono::time_point start, end; + std::chrono::duration DU_duration = + std::chrono::duration::zero(); + std::chrono::duration approxDK_duration = + std::chrono::duration::zero(); +#endif + ImplicitMidpointODESolver(NT initial_time, + NT step, + pts initial_state, + func oracle, + Polytope &boundaries, + Opts &user_options) : + eta(step), + t(initial_time), + xs(initial_state), + F(oracle), + P(boundaries), + options(user_options), + ham(hamiltonian(boundaries)) + { + dim = xs[0].dimension(); + }; + + void step(int k, bool accepted) { + pts partialDerivatives; +#ifdef TIME_KEEPING + start = std::chrono::system_clock::now(); +#endif + partialDerivatives = ham.DU(xs); +#ifdef TIME_KEEPING + end = std::chrono::system_clock::now(); + DU_duration += end - start; +#endif + xs = xs + partialDerivatives * (eta / 2); + xs_prev = xs; + done = false; + nu = VT::Zero(P.equations()); + for (int i = 0; i < options.maxODEStep; i++) { + pts xs_old = xs; + pts xmid = (xs_prev + xs) / 2.0; +#ifdef TIME_KEEPING + start = std::chrono::system_clock::now(); +#endif + partialDerivatives = ham.approxDK(xmid, nu); +#ifdef TIME_KEEPING + end = std::chrono::system_clock::now(); + approxDK_duration += end - start; +#endif + xs = xs_prev + partialDerivatives * (eta); + NT dist = ham.x_norm(xmid, xs - xs_old) / eta; + NT maxdist = dist; + //If the estimate does not change terminate + if (maxdist < options.implicitTol) { + done = true; + num_steps = i; + break; + //If the estimate is very bad sample another velocity + } else if (maxdist > options.convergence_limit) { + xs = xs * std::nan("1"); + done = true; + num_steps = i; + break; + } + } +#ifdef TIME_KEEPING + start = std::chrono::system_clock::now(); +#endif + partialDerivatives = ham.DU(xs); +#ifdef TIME_KEEPING + end = std::chrono::system_clock::now(); + DU_duration += end - start; +#endif + xs = xs + partialDerivatives * (eta / 2); + ham.project(xs); + } + + void steps(int num_steps, bool accepted) { + for (int i = 0; i < num_steps; i++) { + step(i, accepted); + } + } + + Point get_state(int index) { return xs[index]; } + + void set_state(int index, Point p) { xs[index] = p; } + void print_state() { + for (int j = 0; j < xs.size(); j++) { + std::cerr << "state " << j << ": "; + for (unsigned int i = 0; i < xs[j].dimension(); i++) { + std::cerr << xs[j][i] << " "; + } + std::cerr << '\n'; + } + } +}; + +#endif diff --git a/include/ode_solvers/ode_solvers.hpp b/include/ode_solvers/ode_solvers.hpp index 7462f7362..68e730fc4 100644 --- a/include/ode_solvers/ode_solvers.hpp +++ b/include/ode_solvers/ode_solvers.hpp @@ -44,6 +44,7 @@ #include #include "ode_solvers/euler.hpp" +#include "ode_solvers/implicit_midpoint.hpp" #include "ode_solvers/runge_kutta.hpp" #include "ode_solvers/leapfrog.hpp" #include "ode_solvers/richardson_extrapolation.hpp" diff --git a/include/ode_solvers/oracle_functors.hpp b/include/ode_solvers/oracle_functors.hpp index 3c0ac1eae..056e96c3a 100644 --- a/include/ode_solvers/oracle_functors.hpp +++ b/include/ode_solvers/oracle_functors.hpp @@ -142,7 +142,11 @@ struct IsotropicQuadraticFunctor { return xs[i + 1]; // returns derivative } } - + + Point operator()(Point const&x){ + Point y = (-params.alpha)*x; + return y; + } }; @@ -347,7 +351,6 @@ struct GaussianFunctor { Point y = (-2.0 * params.a) * (x - params.x0); return y; } - }; template diff --git a/include/preprocess/crhmc/crhmc_problem.h b/include/preprocess/crhmc/crhmc_problem.h index 1374944ff..5a8a73be8 100644 --- a/include/preprocess/crhmc/crhmc_problem.h +++ b/include/preprocess/crhmc/crhmc_problem.h @@ -24,7 +24,7 @@ #include "preprocess/crhmc/crhmc_utils.h" #include "preprocess/crhmc/lewis_center.h" #include "preprocess/crhmc/opts.h" -#include "sos/barriers/TwoSidedBarrier.h" +#include "preprocess/crhmc/two_sided_barrier.h" #include #include #include @@ -48,7 +48,7 @@ class crhmc_problem { using IndexVector = Eigen::Matrix; using CholObj = PackedChol; using Triple = Eigen::Triplet; - using Barrier = TwoSidedBarrier; + using Barrier = two_sided_barrier; using Tx = FloatArray; using Opts = opts; using Diagonal_MT = Eigen::DiagonalMatrix; diff --git a/include/preprocess/crhmc/lewis_center.h b/include/preprocess/crhmc/lewis_center.h index bae50d622..f6ee7b22e 100644 --- a/include/preprocess/crhmc/lewis_center.h +++ b/include/preprocess/crhmc/lewis_center.h @@ -19,7 +19,7 @@ #include "PackedCSparse/PackedChol.h" #include "preprocess/crhmc/crhmc_utils.h" #include "preprocess/crhmc/opts.h" -#include "sos/barriers/TwoSidedBarrier.h" +#include "preprocess/crhmc/two_sided_barrier.h" #include #include #include diff --git a/include/preprocess/crhmc/opts.h b/include/preprocess/crhmc/opts.h index de7fe4463..dad3a49a5 100644 --- a/include/preprocess/crhmc/opts.h +++ b/include/preprocess/crhmc/opts.h @@ -30,7 +30,8 @@ template class opts { const Type implicitTol = 1e-5; const int maxODEStep = 30; Type initialStep = 0.2; - Type solver_accuracy_threashold=1e-2; + Type convergence_limit = 1e16; + Type solver_accuracy_threshold=1e-2; /*Sampler options*/ bool DynamicWeight = true; //Enable the use of dynamic weights for each variable when sampling diff --git a/include/sos/barriers/TwoSidedBarrier.h b/include/preprocess/crhmc/two_sided_barrier.h similarity index 85% rename from include/sos/barriers/TwoSidedBarrier.h rename to include/preprocess/crhmc/two_sided_barrier.h index d888360ef..8afef162e 100644 --- a/include/sos/barriers/TwoSidedBarrier.h +++ b/include/preprocess/crhmc/two_sided_barrier.h @@ -16,14 +16,14 @@ // The log barrier for the domain {lu <= x <= ub}: // phi(x) = - sum log(x - lb) - sum log(ub - x). -#ifndef TWOSIDEDBARIER_H -#define TWOSIDEDBARIER_H +#ifndef TWO_SIDED_BARIER_H +#define TWO_SIDED_BARIER_H #include "Eigen/Eigen" #include "cartesian_geom/cartesian_kernel.h" #include -template class TwoSidedBarrier { +template class two_sided_barrier { using NT = typename Point::FT; using MT = Eigen::Matrix; @@ -39,6 +39,8 @@ template class TwoSidedBarrier { std::vector freeIdx; VT center; const NT max_step = 1e16; // largest step size + const NT regularization_constant = 1e-20; // small regularization to not have a large inverse + const NT unbounded_center_coord = 1e6; VT extraHessian; //Regularization factor const NT inf = std::numeric_limits::infinity(); @@ -48,7 +50,7 @@ template class TwoSidedBarrier { lb = _lb; ub = _ub; n = lb.rows(); - extraHessian = (1e-20) * VT::Ones(n); + extraHessian = regularization_constant * VT::Ones(n); int x1 = 0, x2 = 0, x3 = 0; for (int i = 0; i < n; i++) { if (lb(i) == -inf) { @@ -61,24 +63,23 @@ template class TwoSidedBarrier { } if (ub(i) == inf && lb(i) == -inf) { freeIdx.push_back(i); - x3++; } } VT c = (ub + lb) / 2; - c(lowerIdx) = lb(lowerIdx) + VT::Ones(x2, 1) * 1e6; - c(upperIdx) = ub(upperIdx) - VT::Ones(x1, 1) * 1e6; + c(lowerIdx) = lb(lowerIdx) + VT::Ones(x2, 1) * unbounded_center_coord; + c(upperIdx) = ub(upperIdx) - VT::Ones(x1, 1) * unbounded_center_coord; c(freeIdx) *= 0.0; center = c; } - TwoSidedBarrier(VT const &_lb, VT const &_ub, int _vdim = 1) { + two_sided_barrier(VT const &_lb, VT const &_ub, int _vdim = 1) { set_bound(_lb, _ub); vdim = _vdim; - extraHessian = (1e-20) * VT::Ones(n); + extraHessian = regularization_constant * VT::Ones(n); } - TwoSidedBarrier() { vdim = 1; } + two_sided_barrier() { vdim = 1; } //barrier function gradient VT gradient(VT const &x) { return (ub - x).cwiseInverse() - (x - lb).cwiseInverse(); @@ -91,10 +92,8 @@ template class TwoSidedBarrier { } //third derivative of the barrier VT tensor(VT const &x) { - VT d = 2 * (((ub - x).cwiseProduct((ub - x))).cwiseProduct((ub - x))) - .cwiseInverse() - - 2 * (((x - lb).cwiseProduct((x - lb))).cwiseProduct((x - lb))) - .cwiseInverse(); + VT d = 2 * (((ub - x).cwiseProduct((ub - x))).cwiseProduct((ub - x))).cwiseInverse() - + 2 * (((x - lb).cwiseProduct((x - lb))).cwiseProduct((x - lb))).cwiseInverse(); return d; } VT quadratic_form_gradient(VT const &x, VT const &u) { diff --git a/include/preprocess/crhmc/weighted_two_sided_barrier.h b/include/preprocess/crhmc/weighted_two_sided_barrier.h new file mode 100644 index 000000000..9cfdab845 --- /dev/null +++ b/include/preprocess/crhmc/weighted_two_sided_barrier.h @@ -0,0 +1,146 @@ +// VolEsti (volume computation and sampling library) + +// Copyright (c) 2012-2020 Vissarion Fisikopoulos +// Copyright (c) 2018-2020 Apostolos Chalkis +// Copyright (c) 2022-2022 Ioannis Iakovidis + +// Contributed and/or modified by Ioannis Iakovidis, as part of Google Summer of +// Code 2022 program. + +// Licensed under GNU LGPL.3, see LICENCE file + +// References +// Yunbum Kook, Yin Tat Lee, Ruoqi Shen, Santosh S. Vempala. "Sampling with +// Riemannian Hamiltonian +// Monte Carlo in a Constrained Space" + +// The log barrier for the domain {lu <= x <= ub}: +// phi(x) = - sum log(x - lb) - sum log(ub - x). +#ifndef WEIGHTED_TWO_SIDED_BARIER_H +#define WEIGHTED_TWO_SIDED_BARIER_H + +#include "Eigen/Eigen" +#include "cartesian_geom/cartesian_kernel.h" +#include + +template class weighted_two_sided_barrier { + + using NT = typename Point::FT; + using MT = Eigen::Matrix; + using VT = Eigen::Matrix; + +public: + VT lb; + VT ub; + int vdim; + int n; + std::vector upperIdx; + std::vector lowerIdx; + std::vector freeIdx; + VT center; + const NT max_step = 1e16; // largest step size + const NT regularization_constant = 1e-20; // small regularization to not have a large inverse + const NT unbounded_center_coord = 1e6; + VT extraHessian; + + const NT inf = std::numeric_limits::infinity(); + + VT w; + + weighted_two_sided_barrier(VT const &_lb, VT const &_ub, VT const &_w, + int _vdim = 1) { + set_bound(_lb, _ub); + w = _w; + vdim = _vdim; + extraHessian = regularization_constant * VT::Ones(n); + } + weighted_two_sided_barrier() { vdim = 1; } + + VT gradient(VT const &x) { + return w.cwiseQuotient(ub - x) - w.cwiseQuotient(x - lb); + } + + VT hessian(VT const &x) { + VT d = w.cwiseQuotient((ub - x).cwiseProduct((ub - x))) + + w.cwiseQuotient((x - lb).cwiseProduct((x - lb))); + return d + extraHessian; + } + VT tensor(VT const &x) { + VT d = 2 * w.cwiseQuotient(((ub - x).cwiseProduct((ub - x))).cwiseProduct((ub - x))) - + 2 * w.cwiseQuotient(((x - lb).cwiseProduct((x - lb))).cwiseProduct((x - lb))); + return d; + } + VT quadratic_form_gradient(VT const &x, VT const &u) { + // Output the -grad of u' (hess phi(x)) u. + + return (u.cwiseProduct(u)).cwiseProduct(tensor(x)); + } + NT step_size(VT const &x, VT const &v) { + // Output the maximum step size from x with direction v or -v. + + // check positive direction + VT temp = (v.array() > 0).select((ub - x).cwiseQuotient(v), max_step); + NT t1 = temp.minCoeff(); + + // check negative direction + temp = (v.array() < 0).select((lb - x).cwiseQuotient(v), max_step); + NT t2 = temp.minCoeff(); + + return std::min(t1, t2); + } + VT boundary_distance(VT const &x) { + // Output the distance of x with its closest boundary for each + // coordinate + return ((x - lb).cwiseMin(ub - x)).cwiseAbs(); + } + + bool feasible(VT const &x) { + return (x.array() > lb.array() && x.array() < ub.array()).all(); + } + + void set_bound(VT const &_lb, VT const &_ub) { + + lb = _lb; + ub = _ub; + n = lb.rows(); + extraHessian = regularization_constant * VT::Ones(n); + int x1 = 0, x2 = 0, x3 = 0; + for (int i = 0; i < n; i++) { + if (lb(i) == -inf) { + upperIdx.push_back(i); + x1++; + } + if (ub(i) == inf) { + lowerIdx.push_back(i); + x2++; + } + if (ub(i) == inf && lb(i) == -inf) { + freeIdx.push_back(i); + } + } + + VT c = (ub + lb) / 2; + + c(lowerIdx) = lb(lowerIdx) + VT::Ones(x2, 1) * unbounded_center_coord; + c(upperIdx) = ub(upperIdx) - VT::Ones(x1, 1) * unbounded_center_coord; + c(freeIdx) *= 0.0; + + center = c; + } + + std::pair boundary(VT const &x) { + // Output the normal at the boundary around x for each barrier. + // Assume: only 1 vector is given + + VT A = VT::Ones(x.rows(), 1); + + VT b = ub; + + b = (x.array() < center.array()).select(-lb, b); + + A = (x.array() < center.array()).select(-A, A); + + return std::make_pair(A, b); + } +}; +#endif diff --git a/include/random_walks/crhmc/additional_units/auto_tuner.hpp b/include/random_walks/crhmc/additional_units/auto_tuner.hpp new file mode 100644 index 000000000..42afc0a77 --- /dev/null +++ b/include/random_walks/crhmc/additional_units/auto_tuner.hpp @@ -0,0 +1,65 @@ +// VolEsti (volume computation and sampling library) + +// Copyright (c) 2012-2020 Vissarion Fisikopoulos +// Copyright (c) 2018-2020 Apostolos Chalkis +// Copyright (c) 2022-2022 Ioannis Iakovidis + +// Contributed and/or modified by Ioannis Iakovidis, as part of Google Summer of +// Code 2022 program. + +// Licensed under GNU LGPL.3, see LICENCE file + +// References +// Yunbum Kook, Yin Tat Lee, Ruoqi Shen, Santosh S. Vempala. "Sampling with +// Riemannian Hamiltonian +// Monte Carlo in a Constrained Space" +#ifndef AUTO_TUNER_HPP +#define AUTO_TUNER_HPP +#include "random_walks/crhmc/additional_units/dynamic_regularizer.hpp" +#include "random_walks/crhmc/additional_units/dynamic_step_size.hpp" +#include "random_walks/crhmc/additional_units/dynamic_weight.hpp" + +/*This class is responsible for calling the additional modules for: +modifying the weights, ode step size and regularizer factor addaptively. +*/ +template +class auto_tuner { + using weight_tuner = dynamic_weight; + using regularizion_tuner = + dynamic_regularizer; + using step_size_tuner = dynamic_step_size; + + using Opts = typename Sampler::Opts; + +public: + Opts options; + weight_tuner *tune_weights; + regularizion_tuner *tune_regularization; + step_size_tuner *tune_step_size; + auto_tuner(Sampler &s) : + options(s.params.options) + { + if (options.DynamicWeight) { + tune_weights = new weight_tuner(s); + } + if (options.DynamicRegularizer) { + tune_regularization = new regularizion_tuner(s); + } + if (options.DynamicStepSize) { + tune_step_size = new step_size_tuner(s); + } + } + void updateModules(Sampler &s, RandomNumberGenerator &rng) + { + if (options.DynamicWeight) { + tune_weights->update_weights(s, rng); + } + if (options.DynamicRegularizer) { + tune_regularization->update_regularization_factor(s, rng); + } + if (options.DynamicStepSize) { + tune_step_size->update_step_size(s); + } + } +}; +#endif diff --git a/include/random_walks/crhmc/additional_units/dynamic_regularizer.hpp b/include/random_walks/crhmc/additional_units/dynamic_regularizer.hpp new file mode 100644 index 000000000..ca213c5a9 --- /dev/null +++ b/include/random_walks/crhmc/additional_units/dynamic_regularizer.hpp @@ -0,0 +1,56 @@ +// VolEsti (volume computation and sampling library) + +// Copyright (c) 2012-2020 Vissarion Fisikopoulos +// Copyright (c) 2018-2020 Apostolos Chalkis +// Copyright (c) 2022-2022 Ioannis Iakovidis + +// Contributed and/or modified by Ioannis Iakovidis, as part of Google Summer of +// Code 2022 program. + +// Licensed under GNU LGPL.3, see LICENCE file + +// References +// Yunbum Kook, Yin Tat Lee, Ruoqi Shen, Santosh S. Vempala. "Sampling with +// Riemannian Hamiltonian +// Monte Carlo in a Constrained Space" +#ifndef DYNAMIC_REGULARIZER_HPP +#define DYNAMIC_REGULARIZER_HPP +#include "Eigen/Eigen" +// Module for updating the extra term we add to the barrier +// This is nessecary for any polytope with free variables +template +class dynamic_regularizer { +public: + using NT = typename Sampler::NT; + using Point = typename Sampler::point; + using VT = Eigen::Matrix; + using Opts = typename Sampler::Opts; + int n; + VT bound; + Opts &options; + VT &extraHessian; + dynamic_regularizer(Sampler &s) : + options(s.params.options), + extraHessian(options.DynamicWeight + ? s.solver->ham.weighted_barrier->extraHessian + : s.solver->ham.barrier->extraHessian) + { + n = s.dim; + bound = VT::Ones(n); + extraHessian = VT::Ones(n); + } + + void update_regularization_factor(Sampler &s, RandomNumberGenerator &rng) + { + VT x = s.x.getCoefficients(); + x = (x.cwiseAbs()).cwiseMax(VT::Ones(n)); + bound = bound.cwiseMax(x); + + if ((2 / (bound.array() * bound.array()) < n * extraHessian.array()).any()) { + extraHessian = (0.5 / n) * (bound.cwiseProduct(bound)).cwiseInverse(); + s.solver->ham.move({s.x, s.v}); + s.v = s.get_direction_with_momentum(n, rng, s.x, Point(n), false); + } + } +}; +#endif diff --git a/include/random_walks/crhmc/additional_units/dynamic_step_size.hpp b/include/random_walks/crhmc/additional_units/dynamic_step_size.hpp new file mode 100644 index 000000000..6b224cc5d --- /dev/null +++ b/include/random_walks/crhmc/additional_units/dynamic_step_size.hpp @@ -0,0 +1,103 @@ +// VolEsti (volume computation and sampling library) + +// Copyright (c) 2012-2020 Vissarion Fisikopoulos +// Copyright (c) 2018-2020 Apostolos Chalkis +// Copyright (c) 2022-2022 Ioannis Iakovidis + +// Contributed and/or modified by Ioannis Iakovidis, as part of Google Summer of +// Code 2022 program. + +// Licensed under GNU LGPL.3, see LICENCE file + +// References +// Yunbum Kook, Yin Tat Lee, Ruoqi Shen, Santosh S. Vempala. "Sampling with +// Riemannian Hamiltonian +// Monte Carlo in a Constrained Space" +#ifndef DYNAMIC_STEP_SIZE_HPP +#define DYNAMIC_STEP_SIZE_HPP +/*Module for dynamically choosing the ODE step size and the velocity momentum*/ +template +class dynamic_step_size { + using NT = typename Sampler::NT; + using Opts = typename Sampler::Opts; + +public: + int consecutiveBadStep = 0; + int iterSinceShrink = 0; + NT rejectSinceShrink = 0; + int ODEStepSinceShrink = 0; + int effectiveStep = 0; + bool warmupFinished = false; + Opts &options; + NT η + NT &momentum; + NT acceptedStep = 0; + NT accumulatedMomentum = 0; + NT nEffectiveStep = 0; // number of effective steps + + dynamic_step_size(Sampler &s) : + options(s.params.options), + eta(s.solver->eta), + momentum(s.params.momentum) + { + if (options.warmUpStep > 0) { + eta = 1e-3; + } else { + warmupFinished = true; + } + } + void update_step_size(Sampler &s) { + acceptedStep = acceptedStep + s.prob; + accumulatedMomentum = s.prob * momentum * accumulatedMomentum + eta; + nEffectiveStep = nEffectiveStep + eta * accumulatedMomentum * s.accept; + + int bad_step = s.prob < 0.5 || s.solver->num_steps == options.maxODEStep ? 1 : 0; + consecutiveBadStep = bad_step * consecutiveBadStep + bad_step; + + NT warmupRatio = nEffectiveStep / options.warmUpStep; + if (warmupRatio < 1 && !warmupFinished && + consecutiveBadStep < options.maxConsecutiveBadStep) { + eta = options.initialStep * std::min(warmupRatio + 1e-2, 1.0); + momentum = 1 - std::min(1.0, eta / options.effectiveStepSize); + return; + } + if (!warmupFinished) { + acceptedStep = 0; + nEffectiveStep = 0; + warmupFinished = true; + } + + iterSinceShrink++; + rejectSinceShrink += 1 - s.prob; + ODEStepSinceShrink += s.solver->num_steps; + + int shrink = 0; + NT shiftedIter = iterSinceShrink + 20 / (1 - momentum); + + NT targetProbability = std::pow((1.0 - momentum), (2 / 3)) / 4; + if (rejectSinceShrink > targetProbability * shiftedIter || + consecutiveBadStep > options.maxConsecutiveBadStep || + ODEStepSinceShrink > options.targetODEStep * shiftedIter) { + shrink = 1; + } + + if (shrink == 1) { + iterSinceShrink = 0; + rejectSinceShrink = 0; + ODEStepSinceShrink = 0; + consecutiveBadStep = 0; + + eta /= options.shrinkFactor; + momentum = 1 - std::min(0.999, eta / options.effectiveStepSize); + + if (eta < options.minStepSize) { + std::cerr << "Algorithm fails to converge even with step size h = " + << eta << "\n"; + exit(1); + } + } + + iterSinceShrink = iterSinceShrink + 1; + } +}; +#endif diff --git a/include/random_walks/crhmc/additional_units/dynamic_weight.hpp b/include/random_walks/crhmc/additional_units/dynamic_weight.hpp new file mode 100644 index 000000000..52917aa5b --- /dev/null +++ b/include/random_walks/crhmc/additional_units/dynamic_weight.hpp @@ -0,0 +1,70 @@ +// VolEsti (volume computation and sampling library) + +// Copyright (c) 2012-2020 Vissarion Fisikopoulos +// Copyright (c) 2018-2020 Apostolos Chalkis +// Copyright (c) 2022-2022 Ioannis Iakovidis + +// Contributed and/or modified by Ioannis Iakovidis, as part of Google Summer of +// Code 2022 program. + +// Licensed under GNU LGPL.3, see LICENCE file + +// References +// Yunbum Kook, Yin Tat Lee, Ruoqi Shen, Santosh S. Vempala. "Sampling with +// Riemannian Hamiltonian +// Monte Carlo in a Constrained Space" +#ifndef DYNAMIC_WEIGHT_HPP +#define DYNAMIC_WEIGHT_HPP +/*Class responsible for updating the weights of the barrier*/ +template +class dynamic_weight { + using NT = typename Sampler::NT; + using Point = typename Sampler::point; + using VT = Eigen::Matrix; + using Opts = typename Sampler::Opts; + +public: + int consecutiveBadStep = 0; + int n; + VT &w; + Opts options; + dynamic_weight(Sampler &s) : + w(s.solver->ham.weighted_barrier->w), + options(s.params.options) + { + n = s.dim; + } + // If we have consecutive bad steps update the weights with + // the help of the leverage scores. + void update_weights(Sampler &s, RandomNumberGenerator &rng) + { + int bad_step = 0; + NT threshold; + if (s.prob < 0.5 || s.solver->num_steps == options.maxODEStep) { + bad_step = 1; + } + consecutiveBadStep = bad_step * consecutiveBadStep + bad_step; + + if (!s.accepted) { + VT lsc = s.solver->ham.lsc; + /*The more bad steps in a row we have the higher we want the threshold to be + In order to change w more drasticaly according to the leverage scores. + So if we have more than 2 bad steps in a row we elect to set the threshold to 4 + else to 16. Not many changes will be possible as the w should be upperbounded by 1*/ + if (consecutiveBadStep > 2) { + threshold = 4; + } else { + threshold = 16; + } + bool changed = (lsc.array() > threshold * w.array()).any(); + w = (lsc.array() > threshold * w.array()) + .select((w * threshold).cwiseMin(VT::Ones(n)), w); + if (changed) { + s.solver->ham.forceUpdate = true; + s.solver->ham.move({s.x, s.v}); + s.v = s.get_direction_with_momentum(n, rng, s.x, Point(n), false); + } + } + } +}; +#endif diff --git a/include/random_walks/crhmc/crhmc_walk.hpp b/include/random_walks/crhmc/crhmc_walk.hpp new file mode 100644 index 000000000..b97d79fa9 --- /dev/null +++ b/include/random_walks/crhmc/crhmc_walk.hpp @@ -0,0 +1,230 @@ +// VolEsti (volume computation and sampling library) + +// Copyright (c) 2012-2020 Vissarion Fisikopoulos +// Copyright (c) 2018-2020 Apostolos Chalkis +// Copyright (c) 2022-2022 Ioannis Iakovidis + +// Contributed and/or modified by Ioannis Iakovidis, as part of Google Summer of +// Code 2022 program. + +// Licensed under GNU LGPL.3, see LICENCE file + +// References +// Yunbum Kook, Yin Tat Lee, Ruoqi Shen, Santosh S. Vempala. "Sampling with +// Riemannian Hamiltonian +// Monte Carlo in a Constrained Space" +#ifndef CRHMC_WALK_HPP +#define CRHMC_WALK_HPP +#include "generators/boost_random_number_generator.hpp" +#include "ode_solvers/ode_solvers.hpp" +#include "random_walks/crhmc/additional_units/auto_tuner.hpp" +#include "random_walks/gaussian_helpers.hpp" +#include +struct CRHMCWalk { + template + < + typename NT, + typename OracleFunctor + > + struct parameters { + using Opts = opts; + NT epsilon; // tolerance in mixing + NT eta = 0.2; // step size + NT momentum; + NT effectiveStepSize = 1; + Opts &options; + parameters(OracleFunctor const &F, + unsigned int dim, + Opts &user_options, + NT epsilon_ = 2) : + options(user_options) + { + epsilon = epsilon_; + eta = 1.0 / (dim * sqrt(F.params.L)); + momentum = 1 - std::min(1.0, eta / effectiveStepSize); + } + }; + + template + < + typename Point, + typename Polytope, + typename RandomNumberGenerator, + typename NegativeGradientFunctor, + typename NegativeLogprobFunctor, + typename Solver + > + struct Walk { + using point = Point; + using pts = std::vector; + using NT = typename Point::FT; + using VT = Eigen::Matrix; + using Sampler = CRHMCWalk::Walk; + + using Opts = typename Polytope::Opts; + + // Hyperparameters of the sampler + parameters ¶ms; + + // Numerical ODE solver + Solver *solver; + + // Dimension + unsigned int dim; + + // Polytope + Polytope &P; + + // Discarded Samples + long total_discarded_samples = 0; + long num_runs = 0; + float discard_ratio = 0; + + // Average acceptance probability + float total_acceptance_prob = 0; + float average_acceptance_prob = 0; + + // Acceptance probability + NT prob; + bool accepted; + NT accept; + bool update_modules; + + // References to xs + Point x, v; + + // Proposal points + Point x_tilde, v_tilde; + + // Gradient function + NegativeGradientFunctor &F; + + // Auto tuner + auto_tuner *module_update; + + // Helper variables + NT H, H_tilde, log_prob, u_logprob; + // Density exponent + NegativeLogprobFunctor &f; +#ifdef TIME_KEEPING + std::chrono::time_point start, end; + std::chrono::duration H_duration = std::chrono::duration::zero(); +#endif + Walk(Polytope &Problem, + Point &p, + NegativeGradientFunctor &neg_grad_f, + NegativeLogprobFunctor &neg_logprob_f, + parameters ¶m) : + params(param), + F(neg_grad_f), + f(neg_logprob_f), + P(Problem) + { + + dim = p.dimension(); + + // Starting point is provided from outside + x = p; + accepted = false; + // Initialize solver + solver = + new Solver(0.0, params.eta, pts{x, x}, F, Problem, params.options); + v = solver->get_state(1); + module_update = new auto_tuner(*this); + update_modules = params.options.DynamicWeight || + params.options.DynamicRegularizer || + params.options.DynamicStepSize; + }; + Point get_direction_with_momentum(unsigned int const &dim, + RandomNumberGenerator &rng, + Point x, + Point v, + NT momentum = 0, + bool normalize = true) + { + Point z = GetDirection::apply(dim, rng, normalize); + solver->ham.move({x, v}); + VT sqrthess = (solver->ham.hess).cwiseSqrt(); + z = Point(sqrthess.cwiseProduct(z.getCoefficients())); + return v * std::sqrt(momentum) + z * std::sqrt(1 - momentum); + } + // Returns the current point in the tranformed in the original space + inline Point getPoint() { return Point(P.T * x.getCoefficients() + P.y); } + + inline void apply(RandomNumberGenerator &rng, + int walk_length = 1, + bool metropolis_filter = true) + { + num_runs++; + // Pick a random velocity with momentum + v = get_direction_with_momentum(dim, rng, x, v, params.momentum, false); + + solver->set_state(0, x); + solver->set_state(1, v); + // Get proposals + solver->steps(walk_length, accepted); + x_tilde = solver->get_state(0); + v_tilde = solver->get_state(1); + + if (metropolis_filter) { +#ifdef TIME_KEEPING + start = std::chrono::system_clock::now(); +#endif + // Calculate initial Hamiltonian + H = solver->ham.hamiltonian(x, v); + // Calculate new Hamiltonian + H_tilde = solver->ham.hamiltonian(x_tilde, Point(dim) - v_tilde); +#ifdef TIME_KEEPING + end = std::chrono::system_clock::now(); + H_duration += end - start; +#endif + NT feasible = solver->ham.feasible(x_tilde.getCoefficients(), + v_tilde.getCoefficients()); + prob = std::min(1.0, exp(H - H_tilde)) * feasible; + + log_prob = log(prob); + total_acceptance_prob += prob; + + // Decide to switch + if (rng.sample_urdist() < prob) { + x = x_tilde; + v = v_tilde; + accepted = true; + } + else { + total_discarded_samples++; + accepted = false; + v = Point(dim) - v; + } + discard_ratio = (1.0 * total_discarded_samples) / num_runs; + average_acceptance_prob = total_acceptance_prob / num_runs; + accept = accepted ? 1 : 0; + } else { + x = x_tilde; + v = v_tilde; + } + if (update_modules) { + module_update->updateModules(*this, rng); + } + } +#ifdef TIME_KEEPING + void print_timing_information() { + std::cerr << "--------------Timing Information--------------\n"; + double DU_time = solver->DU_duration.count(); + double DK_time = solver->approxDK_duration.count(); + double H_time = H_duration.count(); + double total_time = H_time + DK_time + DU_time; + std::cerr << "Computing the Hamiltonian in time, " << H_time << " secs\n"; + std::cerr << "Computing DU partial derivatives in time, " << DU_time + << " secs\n"; + std::cerr << "Computing DK partial derivatives in time, " << DK_time + << " secs\n"; + std::cerr << "H_time + DK_time + DU_time: " << total_time << "\n"; + } +#endif + }; +}; + +#endif diff --git a/include/random_walks/crhmc/hamiltonian.hpp b/include/random_walks/crhmc/hamiltonian.hpp new file mode 100644 index 000000000..6b02e097c --- /dev/null +++ b/include/random_walks/crhmc/hamiltonian.hpp @@ -0,0 +1,233 @@ +// VolEsti (volume computation and sampling library) + +// Copyright (c) 2012-2020 Vissarion Fisikopoulos +// Copyright (c) 2018-2020 Apostolos Chalkis +// Copyright (c) 2022-2022 Ioannis Iakovidis + +// Contributed and/or modified by Ioannis Iakovidis, as part of Google Summer of +// Code 2022 program. + +// Licensed under GNU LGPL.3, see LICENCE file + +// References +// Yunbum Kook, Yin Tat Lee, Ruoqi Shen, Santosh S. Vempala. "Sampling with +// Riemannian Hamiltonian +// Monte Carlo in a Constrained Space" +#ifndef HAMILTONIAN_HPP +#define HAMILTONIAN_HPP +#include "preprocess/crhmc/two_sided_barrier.h" +#include "preprocess/crhmc/weighted_two_sided_barrier.h" +#include "preprocess/crhmc/crhmc_utils.h" +#include + +template +class Hamiltonian { + using VT = typename Polytope::VT; + using NT = typename Polytope::NT; + using MT = typename Polytope::MT; + using Tx = typename Polytope::Tx; + using CholObj = typename Polytope::CholObj; + using Opts = typename Polytope::Opts; + using SpMat = typename Polytope::SpMat; + using pts = std::vector; + using Barrier = two_sided_barrier; + using WeightedBarrier = weighted_two_sided_barrier; + +public: + bool prepared = false; + bool forceUpdate = true; + Polytope &P; + VT hess; + bool dUDx_empty = true; + Point last_dUdx; + CholObj solver; + pts xs; + VT x; + VT dfx; + VT lsc; + NT fx = 0; + int n; + int m; + Barrier *barrier; + WeightedBarrier *weighted_barrier; + Opts &options; + Hamiltonian(Polytope &boundaries) : + P(boundaries), + solver(CholObj(transform_format(boundaries.Asp))), + options(boundaries.options) + { + n = P.dimension(); + m = P.equations(); + x = VT::Zero(n); + xs = {Point(n), Point(n)}; + lsc = VT::Zero(n); + solver.accuracyThreshold = options.solver_accuracy_threshold; + if (options.DynamicWeight) { + weighted_barrier = + new WeightedBarrier(P.barrier.lb, P.barrier.ub, P.w_center); + } + barrier = &P.barrier; + } + + // Compute H(x,v) + NT hamiltonian(Point x, Point v) + { + prepare({x, v}); + pts pd = DK({x, v}); + NT K = 0.5 * v.dot(pd[0]); + NT U = 0.5 * (solver.logdet() + ((hess.array()).log()).sum()); + U = U + fx; + NT E = U + K; + return E; + } + // Helper is nan function for vectors + template + bool isnan(MatrixType x) + { + for (int i = 0; i < x.rows(); i++) { + for (int j = 0; j < x.cols(); j++) { + if (std::isnan(x(i, j))) { + return true; + } + } + } + return false; + } + // Test if the values of x and v are valid and if x is feasible + NT feasible(VT x, VT v) + { + bool feasible_coordinate = true; + if (options.DynamicWeight) { + feasible_coordinate = weighted_barrier->feasible(x); + } else { + feasible_coordinate = barrier->feasible(x); + } + bool r = !isnan(x) && !isnan(v) && feasible_coordinate; + if (r) { + return 1; + } + return 0; + } + // prepare the solver weighted by the hessian + void prepare(pts const &xs) + { + move(xs); + if (!prepared) { + VT Hinv = hess.cwiseInverse(); + solver.decompose((Tx *)Hinv.data()); + } + dUDx_empty = true; + prepared = true; + } + // Computation of the partial derivatives of the K term + pts DK(pts const &x_bar) + { + VT x = x_bar[0].getCoefficients(); + VT v = x_bar[1].getCoefficients(); + move(x_bar); + VT invHessV = v.cwiseQuotient(hess); + VT input_vector = P.Asp * invHessV; + VT out_vector = VT::Zero(m); + solver.solve((Tx *)input_vector.data(), (Tx *)out_vector.data()); + Point dKdv = + Point(invHessV - (P.Asp.transpose() * out_vector).cwiseQuotient(hess)); + + Point dKdx = Point(n); + if (options.DynamicWeight) { + dKdx = Point( + weighted_barrier->quadratic_form_gradient(x, dKdv.getCoefficients()) / + 2); + } else { + dKdx = Point(barrier->quadratic_form_gradient(x, dKdv.getCoefficients()) / + 2); + } + + return {dKdv, dKdx}; + } + // Approximate computation of the partial derivatives of the K term + pts approxDK(pts const &x_bar, VT &nu) + { + VT x = x_bar[0].getCoefficients(); + VT v = x_bar[1].getCoefficients(); + move(x_bar); + VT dUdv_b = P.Asp * (v - P.Asp.transpose() * nu).cwiseQuotient(hess); + VT out_solver = VT(nu.rows(), nu.cols()); + solver.solve((Tx *)dUdv_b.data(), (Tx *)out_solver.data()); + nu = nu + out_solver; + Point dKdv = Point((v - P.Asp.transpose() * nu).cwiseQuotient(hess)); + Point dKdx = Point(n); + if (options.DynamicWeight) { + dKdx = Point( + weighted_barrier->quadratic_form_gradient(x, dKdv.getCoefficients()) / + 2); + } else { + dKdx = Point(barrier->quadratic_form_gradient(x, dKdv.getCoefficients()) / + 2); + } + return {dKdv, dKdx}; + } + // Compute the partial derivatives of one term + // This is only dependent on x and so DU/Dv=0 + pts DU(pts const &x_bar) + { + VT x = x_bar[0].getCoefficients(); + move(x_bar); + if (!prepared || dUDx_empty) { + prepare(x_bar); + solver.leverageScoreComplement((Tx *)lsc.data()); + + if (options.DynamicWeight) { + last_dUdx = Point(-(weighted_barrier->tensor(x).cwiseProduct(lsc)) + .cwiseQuotient(2 * hess) - + dfx); + } else { + last_dUdx = Point( + -(barrier->tensor(x).cwiseProduct(lsc)).cwiseQuotient(2 * hess) - + dfx); + } + dUDx_empty = false; + } + return {Point(n), last_dUdx}; + } + // Compute the computations involving only x iff x has been changed + // Else they are stored + void move(pts const &y) + { + if (y[0] == xs[0] && !forceUpdate) { + return; + } + xs = y; + x = xs[0].getCoefficients(); + VT h; + std::tie(fx, dfx, h) = P.f_oracle(x); + if (options.DynamicWeight) { + hess = weighted_barrier->hessian(x) + h; + } else { + hess = barrier->hessian(x) + h; + } + + forceUpdate = false; + prepared = false; + } + // Project x to the polytope + void project(pts &xs) + { + move(xs); + VT x = xs[0].getCoefficients(); + int m = P.Asp.rows(); + VT out_vector = VT(m); + VT in_vector = P.b - P.Asp * x; + solver.solve((Tx *)in_vector.data(), (Tx *)out_vector.data()); + out_vector = P.Asp.transpose() * out_vector; + xs[0] = xs[0] + Point((out_vector).cwiseQuotient(hess)); + } + // Get the inner product of x and ds weighted by the hessian + NT x_norm(pts const &xs, pts const &dx) + { + move(xs); + VT dx_x = dx[0].getCoefficients(); + VT r = (dx_x.cwiseProduct(dx_x)).cwiseProduct(hess); + return r.sum(); + } +}; +#endif diff --git a/include/random_walks/random_walks.hpp b/include/random_walks/random_walks.hpp index 0d123fc4f..cc5dc089a 100644 --- a/include/random_walks/random_walks.hpp +++ b/include/random_walks/random_walks.hpp @@ -27,5 +27,5 @@ #include "random_walks/uniform_accelerated_billiard_walk_parallel.hpp" #include "random_walks/hamiltonian_monte_carlo_walk.hpp" #include "random_walks/langevin_walk.hpp" - +#include "random_walks/crhmc/crhmc_walk.hpp" #endif // RANDOM_WALKS_RANDOM_WALKS_HPP diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index b3ff5f941..eeaecabcd 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -237,7 +237,8 @@ else () add_test(NAME root_finders_test_root_finders COMMAND root_finders_test -tc=root_finders) - add_executable (benchmarks_crhmc benchmarks_crhmc.cpp ) + #add_executable (benchmarks_crhmc benchmarks_crhmc.cpp ) + #add_executable (benchmarks_crhmc_sampling benchmarks_crhmc_sampling.cpp ) add_executable (crhmc_polytope_preparation_test crhmc_polytope_preparation_test.cpp $) add_test(NAME crhmc_polytope_test_preparation @@ -318,6 +319,12 @@ else () add_test(NAME logconcave_sampling_test_exponential_biomass_sampling COMMAND logconcave_sampling_test -tc=exponential_biomass_sampling) + add_executable (crhmc_sampling_test crhmc_sampling_test.cpp $) + add_test(NAME crhmc_sampling_test_crhmc + COMMAND crhmc_sampling_test -tc=crhmc) + add_test(NAME crhmc_test_polytope_sampling + COMMAND crhmc_sampling_test -tc=test_polytope_sampling_crhmc) + add_executable (simple_mc_integration simple_mc_integration.cpp $) add_test(NAME simple_mc_integration_over_limits COMMAND simple_mc_integration -tc=rectangle) @@ -337,11 +344,16 @@ else () add_test(NAME order_polytope_line_intersect COMMAND order_polytope -tc=line_intersect) add_test(NAME order_polytope_reflection COMMAND order_polytope -tc=reflection) add_test(NAME order_polytope_vec_mult COMMAND order_polytope -tc=vec_mult) - - set(ADDITIONAL_FLAGS "-DSIMD_LEN=0 -march=native -DTIME_KEEPING") - set_target_properties(benchmarks_crhmc PROPERTIES COMPILE_FLAGS ${ADDITIONAL_FLAGS}) - set_target_properties(crhmc_polytope_preparation_test PROPERTIES COMPILE_FLAGS ${ADDITIONAL_FLAGS}) - + set(ADDITIONAL_FLAGS "-march=native -DSIMD_LEN=0 -DTIME_KEEPING") + + #set_target_properties(benchmarks_crhmc + # PROPERTIES COMPILE_FLAGS ${ADDITIONAL_FLAGS}) + #set_target_properties(benchmarks_crhmc_sampling + # PROPERTIES COMPILE_FLAGS ${ADDITIONAL_FLAGS}) + set_target_properties(crhmc_polytope_preparation_test + PROPERTIES COMPILE_FLAGS ${ADDITIONAL_FLAGS}) + set_target_properties(crhmc_sampling_test + PROPERTIES COMPILE_FLAGS ${ADDITIONAL_FLAGS}) TARGET_LINK_LIBRARIES(new_volume_example ${LP_SOLVE} ${MKL_LINK} coverage_config) TARGET_LINK_LIBRARIES(new_volume_example ${LP_SOLVE} coverage_config) TARGET_LINK_LIBRARIES(volume_sob_hpolytope ${LP_SOLVE} coverage_config) @@ -360,13 +372,15 @@ else () TARGET_LINK_LIBRARIES(benchmarks_sob ${LP_SOLVE} ${MKL_LINK} coverage_config) TARGET_LINK_LIBRARIES(benchmarks_cg ${LP_SOLVE} ${MKL_LINK} coverage_config) TARGET_LINK_LIBRARIES(benchmarks_cb ${LP_SOLVE} ${MKL_LINK} coverage_config) - TARGET_LINK_LIBRARIES(benchmarks_crhmc ${LP_SOLVE} ${MKL_LINK} ${QD_LIB} coverage_config) + #TARGET_LINK_LIBRARIES(benchmarks_crhmc_sampling ${LP_SOLVE} ${MKL_LINK} ${QD_LIB} coverage_config) + #TARGET_LINK_LIBRARIES(benchmarks_crhmc ${LP_SOLVE} ${MKL_LINK} ${QD_LIB} coverage_config) TARGET_LINK_LIBRARIES(simple_mc_integration ${LP_SOLVE} ${MKL_LINK} coverage_config) - TARGET_LINK_LIBRARIES(ode_solvers_test ${LP_SOLVE} ${IFOPT} ${IFOPT_IPOPT} ${PTHREAD} ${GMP} ${MPSOLVE} ${FFTW3} ${MKL_LINK} coverage_config) + TARGET_LINK_LIBRARIES(ode_solvers_test ${LP_SOLVE} ${IFOPT} ${IFOPT_IPOPT} ${PTHREAD} ${GMP} ${MPSOLVE} ${FFTW3} ${MKL_LINK} ${QD_LIB} coverage_config) TARGET_LINK_LIBRARIES(boundary_oracles_test ${LP_SOLVE} ${IFOPT} ${IFOPT_IPOPT} ${PTHREAD} ${GMP} ${MPSOLVE} ${FFTW3} ${MKL_LINK} coverage_config) TARGET_LINK_LIBRARIES(root_finders_test ${PTHREAD} ${GMP} ${MPSOLVE} ${FFTW3} ${MKL_LINK} coverage_config) TARGET_LINK_LIBRARIES(crhmc_polytope_preparation_test ${PTHREAD} ${GMP} ${MPSOLVE} ${FFTW3} ${MKL_LINK} ${QD_LIB} coverage_config) TARGET_LINK_LIBRARIES(logconcave_sampling_test ${LP_SOLVE} ${IFOPT} ${IFOPT_IPOPT} ${PTHREAD} ${GMP} ${MPSOLVE} ${FFTW3} ${MKL_LINK} coverage_config) + TARGET_LINK_LIBRARIES(crhmc_sampling_test ${LP_SOLVE} ${IFOPT} ${IFOPT_IPOPT} ${PTHREAD} ${GMP} ${MPSOLVE} ${FFTW3} ${MKL_LINK} ${QD_LIB} coverage_config) TARGET_LINK_LIBRARIES(order_polytope ${LP_SOLVE} coverage_config) diff --git a/test/benchmarks_crhmc_sampling.cpp b/test/benchmarks_crhmc_sampling.cpp new file mode 100644 index 000000000..27460b5be --- /dev/null +++ b/test/benchmarks_crhmc_sampling.cpp @@ -0,0 +1,387 @@ +// VolEsti (volume computation and sampling library) + +// Copyright (c) 2012-2020 Vissarion Fisikopoulos +// Copyright (c) 2018-2020 Apostolos Chalkis +// Copyright (c) 2022-2022 Ioannis Iakovidis + +// Contributed and/or modified by Ioannis Iakovidis, as part of Google Summer of +// Code 2022 program. + +// Licensed under GNU LGPL.3, see LICENCE file + +// References +// Yunbum Kook, Yin Tat Lee, Ruoqi Shen, Santosh S. Vempala. "Sampling with +// Riemannian Hamiltonian +// Monte Carlo in a Constrained Space" +#include "Eigen/Eigen" +#include "cartesian_geom/cartesian_kernel.h" +#include "convex_bodies/hpolytope.h" +#include "diagnostics/diagnostics.hpp" +#include "generators/known_polytope_generators.h" +#include "misc/misc.h" +#include "ode_solvers.hpp" +#include "preprocess/crhmc/crhmc_input.h" +#include "preprocess/crhmc/crhmc_problem.h" +#include "random.hpp" +#include "random/normal_distribution.hpp" +#include "random/uniform_int.hpp" +#include "random/uniform_real_distribution.hpp" +#include "random_walks/random_walks.hpp" +#include +#include +#include +#include "preprocess/svd_rounding.hpp" +template +Polytope read_polytope(std::string filename) { + std::ifstream inp; + std::vector> Pin; + inp.open(filename, std::ifstream::in); + read_pointset(inp, Pin); + Polytope P(Pin); + return P; +} +template +struct SimulationStats { + std::string method; + unsigned int walk_length; + unsigned int min_ess = 0; + NT max_psrf = NT(0); + NT time_per_draw = NT(0); + NT time_per_independent_sample = NT(0); + NT average_acceptance_prob = NT(0); + NT step_size = NT(0); + + friend std::ostream &operator<<(std::ostream &out, + const SimulationStats &stats) + { + out << stats.method << "," << stats.walk_length << "," << stats.min_ess + << "," << stats.max_psrf << "," << stats.time_per_draw << "," + << stats.time_per_independent_sample << "," + << stats.average_acceptance_prob << "," + << "," << stats.step_size << std::endl; + return out; + } +}; +struct InnerBallFunctor { + + // Gaussian density centered at the inner ball center + template + struct parameters { + unsigned int order; + NT L; // Lipschitz constant for gradient + NT m; // Strong convexity constant + NT kappa; // Condition number + NT R0; + NT sigma; + Point x0; + + parameters(Point x0_, NT R0_) + : order(2), L(1), m(1), kappa(1), x0(x0_), R0(R0_), sigma(1){}; + }; + + template + struct GradientFunctor { + typedef typename Point::FT NT; + typedef std::vector pts; + + parameters ¶ms; + + GradientFunctor(parameters ¶ms_) : params(params_){}; + + // The index i represents the state vector index + Point operator()(unsigned int const &i, pts const &xs, NT const &t) const + { + if (i == params.order - 1) { + Point y = (-1.0 / pow(params.sigma, 2)) * (xs[0] - params.x0); + return y; + } else { + return xs[i + 1]; // returns derivative + } + } + Point operator()(Point const &x) const { + Point y = (-1.0 / pow(params.sigma, 2)) * (x - params.x0); + return y; + } + }; + + template + struct FunctionFunctor { + typedef typename Point::FT NT; + + parameters ¶ms; + + FunctionFunctor(parameters ¶ms_) : params(params_){}; + + // The index i represents the state vector index + NT operator()(Point const &x) const { + Point y = x - params.x0; + return 1.0 / (2 * pow(params.sigma, 2)) * y.dot(y); + } + }; + template + struct Hess { + typedef typename Point::FT NT; + + parameters ¶ms; + Hess(parameters ¶ms_) : params(params_){}; + + Point operator()(Point const &x) const { + return (1.0 / pow(params.sigma, 2)) * Point::all_ones(x.dimension()); + } + }; +}; + +inline bool exists_check(const std::string &name) { + std::ifstream f(name.c_str()); + return f.good(); +} +template +NT check_interval_psrf(MT &samples, NT target = NT(1.2)) { + NT max_psrf = NT(0); + VT intv_psrf = interval_psrf(samples); + unsigned int d = intv_psrf.rows(); + for (unsigned int i = 0; i < d; i++) { + assert(intv_psrf(i) < target); + if (intv_psrf(i) > max_psrf) + max_psrf = intv_psrf(i); + } + return max_psrf; +} +template +std::vector> benchmark_polytope_sampling( + Polytope &P, NT eta = NT(-1), unsigned int walk_length = 1, + double target_time = std::numeric_limits::max(), bool rounding = false, + bool centered = false, unsigned int max_draws = 80000, + unsigned int num_burns = 20000) +{ + using Kernel = Cartesian; + using Point = typename Kernel::Point; + using MT = typename Polytope::MT; + using VT = typename Polytope::VT; + using Func = InnerBallFunctor::FunctionFunctor; + using Grad = InnerBallFunctor::GradientFunctor; + using Hess = InnerBallFunctor::Hess; + using Input = crhmc_input; + using CrhmcProblem = crhmc_problem; + using Opts = opts; + using Solver = ImplicitMidpointODESolver; + using RandomNumberGenerator = BoostRandomNumberGenerator; + + SimulationStats rdhr_stats; + SimulationStats crhmc_stats; + + std::pair inner_ball; + if (centered) { + inner_ball.first = Point(P.dimension()); + inner_ball.second = NT(1); // dummy radius (not correct one) + } else { + inner_ball = P.ComputeInnerBall(); + } + + // Random number generator + RandomNumberGenerator rng(1); + + // Chebyshev center + Point x0 = inner_ball.first; + NT R0 = inner_ball.second; + unsigned int dim = x0.dimension(); + + if (rounding) { + std::cout << "SVD Rounding" << std::endl; + svd_rounding(P, inner_ball, walk_length, + rng); + } + // Declare oracles + InnerBallFunctor::parameters params(x0, R0); + + Grad F(params); + Func f(params); + Hess H(params); + int max_actual_draws = max_draws - num_burns; + unsigned int min_ess = 0; + + MT samples; + samples.resize(dim, max_actual_draws); + NT ETA; + NT max_psrf; + + std::chrono::time_point start, stop; + Opts options; + CRHMCWalk::parameters crhmc_params(F, dim, options); + Input input = Input(P.dimension(), f, F, H); + input.Aineq = P.get_mat(); + input.bineq = P.get_vec(); + + CrhmcProblem crhmc_problem = CrhmcProblem(input); + Point x_start(crhmc_problem.center); + CRHMCWalk::Walk + crhmc(crhmc_problem, x_start, F, f, crhmc_params); + + min_ess = 0; + + std::cout + << "Constrained Riemannian Hamiltonian Monte Carlo (Gaussian Density)" + << std::endl; + + if (eta > 0) + crhmc.solver->eta = eta; + + std::cout << "Burn-in" << std::endl; + + for (unsigned int i = 0; i < num_burns; i++) { + if (i % 1000 == 0) + std::cout << "."; + crhmc.apply(rng, 1); + } + + std::cout << std::endl; + std::cout << "Sampling" << std::endl; + + start = std::chrono::high_resolution_clock::now(); + for (unsigned int i = 0; i < max_actual_draws; i++) { + for (int k = 0; k < walk_length; k++) { + crhmc.apply(rng, 1); + } + samples.col(i) = crhmc.getPoint().getCoefficients(); + if (i % 1000 == 0 && i > 0) + std::cout << "."; + } + stop = std::chrono::high_resolution_clock::now(); + + ETA = (NT)std::chrono::duration_cast(stop - start) + .count(); + + std::cout << std::endl; +#ifdef TIME_KEEPING + std::chrono::duration total_time = stop - start; + std::cerr << "Total time: " << total_time.count() << "\n"; + assert(total_time.count() < target_time); + std::cout << "Assertion (preparation_time< " << target_time + << " secs) passed!" << std::endl + << std::endl; + crhmc.print_timing_information(); +#endif + print_diagnostics(samples, min_ess, std::cout); + std::cout << "min ess " << min_ess << "us" << std::endl; + std::cout << "Average time per sample: " << ETA / max_actual_draws << "us" + << std::endl; + std::cout << "Average time per independent sample: " << ETA / min_ess << "us" + << std::endl; + std::cout << "Step size (final): " << crhmc.solver->eta << std::endl; + std::cout << "Discard Ratio: " << crhmc.discard_ratio << std::endl; + std::cout << "Average Acceptance Probability: " + << crhmc.average_acceptance_prob << std::endl; + max_psrf = check_interval_psrf(samples); + std::cout << "max_psrf: " << max_psrf << std::endl; + std::cout << std::endl; + + crhmc_stats.method = "CRHMC"; + crhmc_stats.walk_length = walk_length; + crhmc_stats.min_ess = min_ess; + crhmc_stats.max_psrf = max_psrf; + crhmc_stats.time_per_draw = ETA / max_actual_draws; + crhmc_stats.time_per_independent_sample = ETA / min_ess; + crhmc_stats.step_size = crhmc.solver->eta; + crhmc_stats.average_acceptance_prob = crhmc.average_acceptance_prob; + + return std::vector>{rdhr_stats, crhmc_stats}; +} + +template +void test_benchmark_polytope( + HPolytope &P, std::string &name, bool centered, + double target_time = std::numeric_limits::max(), int walk_length = 1) +{ + std::cout << "CRHMC polytope preparation for " << name << std::endl; + std::vector> results; + NT step_size = 0; + std::pair inner_ball; + std::ofstream outfile; + std::cout << name << std::endl; + outfile.open("results_" + name + "_new.txt"); + P.normalize(); + inner_ball = P.ComputeInnerBall(); + step_size = inner_ball.second / 10; + results = benchmark_polytope_sampling(P, step_size, walk_length, target_time, + false, centered); + outfile << results[0]; + outfile << results[1]; + + outfile.close(); +} + +template +void call_test_benchmark_polytope() { + using Kernel = Cartesian; + using Point = typename Kernel::Point; + using Hpolytope = HPolytope; + { + Hpolytope P = generate_skinny_cube(100, false); + std::string name = "100_skinny_cube"; + bool centered = false; + double target_time = 20; // secs + test_benchmark_polytope(P, name, false, target_time); + } + + { + Hpolytope P = generate_cross(5, false); + std::string name = "5_cross"; + bool centered = false; + double target_time = 10; // secs + test_benchmark_polytope(P, name, centered, target_time); + } + + { + Hpolytope P = generate_simplex(100, false); + std::string name = "100_simplex"; + bool centered = false; + double target_time = 15; // secs + test_benchmark_polytope(P, name, centered, target_time); + } + + { + Hpolytope P = generate_prod_simplex(50, false); + std::string name = "50_prod_simplex"; + bool centered = false; + double target_time = 15; // secs + test_benchmark_polytope(P, name, centered, target_time); + } + + { + Hpolytope P = generate_birkhoff(10); + std::string name = "10_birkhoff"; + bool centered = false; + double target_time = 15; // secs + test_benchmark_polytope(P, name, centered, target_time); + } + + if (exists_check("netlib/afiro.ine")) + { + Hpolytope P = read_polytope("netlib/afiro.ine"); + std::string name = "afiro"; + bool centered = true; + double target_time = 100; // secs + test_benchmark_polytope(P, name, centered, target_time); + } + + if (exists_check("metabolic_full_dim/polytope_e_coli.ine")) + { + Hpolytope P = + read_polytope("metabolic_full_dim/polytope_e_coli.ine"); + std::string name = "e_coli"; + bool centered = true; + double target_time = 600; // secs + test_benchmark_polytope(P, name, centered, target_time); + } +} + +int main() { + + std::cout + << "---------------CRHMC polytope sampling benchmarking---------------" + << std::endl + << std::endl; + call_test_benchmark_polytope(); + return 0; +} diff --git a/test/crhmc_sampling_test.cpp b/test/crhmc_sampling_test.cpp new file mode 100644 index 000000000..2bd1b7995 --- /dev/null +++ b/test/crhmc_sampling_test.cpp @@ -0,0 +1,506 @@ +// VolEsti (volume computation and sampling library) + +// Copyright (c) 2012-2020 Vissarion Fisikopoulos +// Copyright (c) 2018-2020 Apostolos Chalkis +// Copyright (c) 2022-2022 Ioannis Iakovidis + +// Contributed and/or modified by Ioannis Iakovidis, as part of Google Summer +// of Code 2022 program. + +// Licensed under GNU LGPL.3, see LICENCE file +#include "Eigen/Eigen" +#include "diagnostics/diagnostics.hpp" +#include "doctest.h" +#include "generators/known_polytope_generators.h" +#include "misc/misc.h" +#include "ode_solvers.hpp" +#include "preprocess/crhmc/crhmc_input.h" +#include "preprocess/crhmc/crhmc_problem.h" +#include "random.hpp" +#include "random/normal_distribution.hpp" +#include "random/uniform_int.hpp" +#include "random/uniform_real_distribution.hpp" +#include "random_walks/random_walks.hpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "preprocess/svd_rounding.hpp" +struct InnerBallFunctor { + + // Gaussian density centered at the inner ball center + template + struct parameters { + unsigned int order; + NT L; // Lipschitz constant for gradient + NT m; // Strong convexity constant + NT kappa; // Condition number + NT R0; + NT sigma; + Point x0; + + parameters(Point x0_, NT R0_) + : order(2), L(1), m(1), kappa(1), x0(x0_), R0(R0_), sigma(1){}; + }; + + template + struct GradientFunctor { + using NT = typename Point::FT; + using pts = std::vector; + + parameters ¶ms; + + GradientFunctor(parameters ¶ms_) : params(params_){}; + + // The index i represents the state vector index + Point operator()(unsigned int const &i, pts const &xs, NT const &t) const { + if (i == params.order - 1) { + Point y = (-1.0 / pow(params.sigma, 2)) * (xs[0] - params.x0); + return y; + } else { + return xs[i + 1]; // returns derivative + } + } + Point operator()(Point const &x) const { + Point y = (-1.0 / pow(params.sigma, 2)) * (x - params.x0); + return y; + } + }; + + template + struct FunctionFunctor { + using NT = typename Point::FT; + + parameters ¶ms; + + FunctionFunctor(parameters ¶ms_) : params(params_){}; + + // The index i represents the state vector index + NT operator()(Point const &x) const { + Point y = x - params.x0; + return 1.0 / (2 * pow(params.sigma, 2)) * y.dot(y); + } + }; + template + struct HessianFunctor { + using NT = typename Point::FT; + + parameters ¶ms; + HessianFunctor(parameters ¶ms_) : params(params_){}; + + Point operator()(Point const &x) const { + return (1.0 / pow(params.sigma, 2)) * Point::all_ones(x.dimension()); + } + }; +}; +struct CustomFunctor { + + // Custom density with neg log prob equal to || x ||^2 + 1^T x + template + struct parameters { + unsigned int order; + NT L; // Lipschitz constant for gradient + NT m; // Strong convexity constant + NT kappa; // Condition number + + parameters() : order(2), L(2), m(2), kappa(1){}; + + parameters(unsigned int order_) : order(order), L(2), m(2), kappa(1) {} + }; + + template + struct GradientFunctor { + using NT = typename Point::FT; + using pts = std::vector; + + parameters params; + + GradientFunctor(){}; + + // The index i represents the state vector index + Point operator()(unsigned int const &i, pts const &xs, NT const &t) const { + if (i == params.order - 1) { + Point y = (-1.0) * Point::all_ones(xs[0].dimension()); + y = y + (-2.0) * xs[0]; + return y; + } else { + return xs[i + 1]; // returns derivative + } + } + Point operator()(Point const &x) const { + Point y = (-1.0) * Point::all_ones(x.dimension()); + y = y + (-2.0) * x; + return y; + } + }; + + template + struct FunctionFunctor { + using NT = typename Point::FT; + + parameters params; + + FunctionFunctor(){}; + + // The index i represents the state vector index + NT operator()(Point const &x) const { return x.dot(x) + x.sum(); } + }; + template + struct HessianFunctor { + using NT = typename Point::FT; + Point operator()(Point const &x) const { + return 2 * Point::all_ones(x.dimension()); + } + }; +}; +template +NT check_interval_psrf(MT &samples, NT target = NT(1.2)) { + NT max_psrf = NT(0); + VT intv_psrf = interval_psrf(samples); + unsigned int d = intv_psrf.rows(); + for (unsigned int i = 0; i < d; i++) { + CHECK(intv_psrf(i) < target); + if (intv_psrf(i) > max_psrf) + max_psrf = intv_psrf(i); + } + return max_psrf; +} + +template +void check_ergodic_mean_norm(Sampler &sampler, RandomNumberGenerator &rng, + Point &mean, unsigned int dim, + int n_samples = 1500, int skip_samples = 750, + NT target = NT(0), NT tol = 5e-1) +{ + + auto start = std::chrono::high_resolution_clock::now(); + + for (int i = 0; i < n_samples; i++) { + sampler.apply(rng, 1); + if (i >= skip_samples) { + Point x = sampler.getPoint(); + mean = mean + x; + } + +#ifdef VOLESTI_DEBUG + std::cout << sampler.getPoint().x.getCoefficients().transpose() + << std::endl; +#endif + } + + auto stop = std::chrono::high_resolution_clock::now(); + + long ETA = + (long)std::chrono::duration_cast(stop - start) + .count(); + + mean = (1.0 / (n_samples - skip_samples)) * mean; + + NT error = abs(NT(mean.dot(mean)) - target); + + if (target != NT(0)) + error /= abs(target); + + std::cout << "Dimensionality: " << dim << std::endl; + std::cout << "Target ergodic mean norm: " << target << std::endl; + std::cout << "Error (relative if possible) after " << n_samples + << " samples: " << error << std::endl; + std::cout << "ETA (us): " << ETA << std::endl + << std::endl; + + CHECK(error < tol); +} +template +Polytope read_polytope(std::string filename) { + std::ifstream inp; + std::vector> Pin; + inp.open(filename, std::ifstream::in); + read_pointset(inp, Pin); + Polytope P(Pin); + return P; +} + +template +void crhmc_polytope_sampling( + Polytope &P, NT eta = NT(-1), unsigned int walk_length = 1, + bool rounding = false, bool centered = false, + unsigned int max_draws = 80000, unsigned int num_burns = 20000) +{ + using Kernel = Cartesian; + using Point = typename Kernel::Point; + using RandomNumberGenerator = BoostRandomNumberGenerator; + using NegativeGradientFunctor = InnerBallFunctor::GradientFunctor; + using NegativeLogprobFunctor = InnerBallFunctor::FunctionFunctor; + using HessianFunctor = InnerBallFunctor::HessianFunctor; + using MT = typename Polytope::MT; + using VT = typename Polytope::VT; + using Input = crhmc_input; + using CrhmcProblem = crhmc_problem; + using Opts = opts; + using Solver = ImplicitMidpointODESolver; + + std::pair inner_ball; + if (centered) { + inner_ball.first = Point(P.dimension()); + inner_ball.second = NT(1); // dummy radius (not correct one) + } else { + inner_ball = P.ComputeInnerBall(); + } + + // Random number generator + RandomNumberGenerator rng(1); + + // Chebyshev center + Point x0 = inner_ball.first; + NT R0 = inner_ball.second; + unsigned int dim = x0.dimension(); + + if (rounding) { + std::cout << "SVD Rounding" << std::endl; + svd_rounding(P, inner_ball, walk_length, + rng); + } + + // Declare oracles + InnerBallFunctor::parameters params(x0, R0); + + NegativeGradientFunctor F(params); + NegativeLogprobFunctor f(params); + HessianFunctor H(params); + int max_actual_draws = max_draws - num_burns; + unsigned int min_ess = 0; + + MT samples; + samples.resize(dim, max_actual_draws); + NT ETA; + NT max_psrf; + + Opts options; + CRHMCWalk::parameters crhmc_params(F, dim, + options); + Input input = Input(P.dimension(), f, F, H); + input.Aineq = P.get_mat(); + input.bineq = P.get_vec(); + + CrhmcProblem crhmc_problem = CrhmcProblem(input); + Point x_start(crhmc_problem.center); + CRHMCWalk::Walk + crhmc(crhmc_problem, x_start, F, f, crhmc_params); + + min_ess = 0; + + std::cout + << "Constrained Riemannian Hamiltonian Monte Carlo (Gaussian Density)" + << std::endl; + + if (eta > 0) + crhmc.solver->eta = eta; + + std::cout << "Burn-in" << std::endl; + + for (unsigned int i = 0; i < num_burns; i++) { + if (i % 1000 == 0) + std::cout << "."; + crhmc.apply(rng, 1); + } + + std::cout << std::endl; + std::cout << "Sampling" << std::endl; + + for (unsigned int i = 0; i < max_actual_draws; i++) { + for (int k = 0; k < walk_length; k++) { + crhmc.apply(rng, 1); + } + samples.col(i) = crhmc.getPoint().getCoefficients(); + if (i % 1000 == 0 && i > 0) + std::cout << "."; + } + std::cout << std::endl; + std::cout << "Step size (final): " << crhmc.solver->eta << std::endl; + std::cout << "Discard Ratio: " << crhmc.discard_ratio << std::endl; + std::cout << "Average Acceptance Probability: " + << crhmc.average_acceptance_prob << std::endl; + max_psrf = check_interval_psrf(samples); + std::cout << "max_psrf: " << max_psrf << std::endl; + std::cout << std::endl; +} +inline bool exists_check(const std::string &name) { + std::ifstream f(name.c_str()); + return f.good(); +} + +template +void test_sampling_polytope(HPolytope &P, std::string &name, bool centered, + int walk_length = 1) { + NT step_size = 0; + std::pair inner_ball; + std::cout << name << std::endl; + P.normalize(); + inner_ball = P.ComputeInnerBall(); + step_size = inner_ball.second / 10; + crhmc_polytope_sampling(P, step_size, walk_length, false, centered); +} +template +void call_test_sampling_polytope() { + using Kernel = Cartesian; + using Point = typename Kernel::Point; + using Hpolytope = HPolytope; + std::cout << " ---Sampling polytopes " << std::endl; + + { + Hpolytope P = generate_skinny_cube(100, false); + std::string name = "100_skinny_cube"; + bool centered = false; + test_sampling_polytope(P, name, false); + } + + { + Hpolytope P = generate_cross(5, false); + std::string name = "5_cross"; + bool centered = false; + test_sampling_polytope(P, name, centered); + } + + { + Hpolytope P = generate_simplex(100, false); + std::string name = "100_simplex"; + bool centered = false; + test_sampling_polytope(P, name, centered); + } + + { + Hpolytope P = generate_prod_simplex(50, false); + std::string name = "50_prod_simplex"; + bool centered = false; + test_sampling_polytope(P, name, centered); + } + + { + Hpolytope P = generate_birkhoff(10); + std::string name = "10_birkhoff"; + bool centered = false; + test_sampling_polytope(P, name, centered); + } +} + +template +void benchmark_cube_crhmc() { + using Kernel = Cartesian; + using Point = typename Kernel::Point; + using pts = std::vector; + using VT = Eigen::Matrix; + using MT = Eigen::Matrix; + using NegativeGradientFunctor = CustomFunctor::GradientFunctor; + using NegativeLogprobFunctor = CustomFunctor::FunctionFunctor; + using Input = + crhmc_input; + using CrhmcProblem = crhmc_problem; + using RandomNumberGenerator = BoostRandomNumberGenerator; + using Solver = ImplicitMidpointODESolver; + using Opts = opts; + NegativeGradientFunctor g; + NegativeLogprobFunctor f; + RandomNumberGenerator rng(1); + Opts options; + unsigned int dim_min = 1; + unsigned int dim_max = 100; + int n_samples = 1000; + long ETA; + std::chrono::time_point start, stop; + + for (unsigned int dim = dim_min; dim <= dim_max; dim++) { + CRHMCWalk::parameters crhmc_params(g, dim, + options); + Input input = Input(dim, f, g); + input.lb = -VT::Ones(dim); + input.ub = VT::Ones(dim); + CrhmcProblem P = CrhmcProblem(input); + Point x0(P.center); + CRHMCWalk::Walk + crhmc(P, x0, g, f, crhmc_params); + start = std::chrono::high_resolution_clock::now(); + for (int i = 0; i < n_samples; i++) + crhmc.apply(rng, 1); + stop = std::chrono::high_resolution_clock::now(); + + ETA = (long)std::chrono::duration_cast(stop - + start) + .count(); + std::cout << ETA << std::endl; + } +} + +template +void test_crhmc() { + using Kernel = Cartesian; + using Point = typename Kernel::Point; + using pts = std::vector; + using VT = Eigen::Matrix; + using MT = Eigen::Matrix; + using NegativeGradientFunctor = + IsotropicQuadraticFunctor::GradientFunctor; + using NegativeLogprobFunctor = + IsotropicQuadraticFunctor::FunctionFunctor; + using Input = + crhmc_input; + using CrhmcProblem = crhmc_problem; + using RandomNumberGenerator = BoostRandomNumberGenerator; + using Solver = ImplicitMidpointODESolver; + using Opts = opts; + IsotropicQuadraticFunctor::parameters params; + params.order = 2; + NegativeGradientFunctor g(params); + NegativeLogprobFunctor f(params); + RandomNumberGenerator rng(1); + unsigned int dim = 10; + Opts options; + CRHMCWalk::parameters crhmc_params(g, dim, + options); + Input input = Input(dim, f, g); + input.lb = -VT::Ones(dim); + input.ub = VT::Ones(dim); + CrhmcProblem P = CrhmcProblem(input); + Point x0(dim); + CRHMCWalk::Walk + crhmc(P, x0, g, f, crhmc_params); + Point mean(dim); + check_ergodic_mean_norm(crhmc, rng, mean, dim, 75000, 37500, NT(0)); +} + +template +void call_test_crhmc() { + std::cout << "--- Testing Constrained Riemannian Hamiltonian Monte Carlo" + << std::endl; + test_crhmc(); +} +template +void call_test_benchmark_cube_crhmc() { + benchmark_cube_crhmc(); +} + +TEST_CASE("crhmc") { + call_test_crhmc(); +} + +TEST_CASE("benchmark_crhmc_cube") { + call_test_benchmark_cube_crhmc(); +} + +TEST_CASE("test_polytope_sampling_crhmc") { + call_test_sampling_polytope(); +} diff --git a/test/ode_solvers_test.cpp b/test/ode_solvers_test.cpp index 4b3a36f11..b8cfd9d6d 100644 --- a/test/ode_solvers_test.cpp +++ b/test/ode_solvers_test.cpp @@ -4,50 +4,53 @@ // Copyright (c) 2018-2020 Apostolos Chalkis // Copyright (c) 2020-2020 Marios Papachristou -// Contributed and/or modified by Marios Papachristou, as part of Google Summer of Code 2020 program. +// Contributed and/or modified by Marios Papachristou, as part of Google Summer +// of Code 2020 program. // Licensed under GNU LGPL.3, see LICENCE file -#include +#include #include #include -#include -#include +#include #include #include -#include +#include +#include -#include "doctest.h" #include "Eigen/Eigen" +#include "doctest.h" +#include "generators/known_polytope_generators.h" #include "ode_solvers.hpp" +#include "preprocess/crhmc/crhmc_input.h" +#include "preprocess/crhmc/crhmc_problem.h" #include "random.hpp" -#include "random/uniform_int.hpp" #include "random/normal_distribution.hpp" +#include "random/uniform_int.hpp" #include "random/uniform_real_distribution.hpp" #include "random_walks/random_walks.hpp" -#include "volume/volume_sequence_of_balls.hpp" -#include "volume/volume_cooling_gaussians.hpp" #include "volume/volume_cooling_balls.hpp" -#include "generators/known_polytope_generators.h" +#include "volume/volume_cooling_gaussians.hpp" +#include "volume/volume_sequence_of_balls.hpp" template -void check_norm(Solver &solver, int num_steps, NT target, NT tol=1e-4) { +void check_norm(Solver &solver, int num_steps, NT target, NT tol = 1e-4) { auto start = std::chrono::high_resolution_clock::now(); - #ifndef VOLESTI_DEBUG - solver.steps(num_steps, true); - #else - for (int i = 0; i < num_steps; i++) { - solver.step(i, true); - solver.print_state(); - } - #endif +#ifndef VOLESTI_DEBUG + solver.steps(num_steps, true); +#else + for (int i = 0; i < num_steps; i++) { + solver.step(i, true); + solver.print_state(); + } +#endif auto stop = std::chrono::high_resolution_clock::now(); - long ETA = (long) std::chrono::duration_cast(stop - start).count(); + long ETA = (long)std::chrono::duration_cast(stop - start).count(); NT norm = NT(0); @@ -63,250 +66,304 @@ void check_norm(Solver &solver, int num_steps, NT target, NT tol=1e-4) { std::cout << norm << std::endl; std::cout << "Target Norm: " << target << std::endl; - if (target != NT(0)) error /= target; + if (target != NT(0)) + error /= target; std::cout << "Error (relative if applicable): " << error << std::endl; std::cout << "ETA (us): " << ETA << std::endl << std::endl; CHECK(error < tol); - } template -void check_index_norm_ub(Solver &solver, int num_steps, int index, NT target, NT tol=1e-2) { +void check_index_norm_ub(Solver &solver, int num_steps, int index, NT target, + NT tol = 1e-2) { std::cout << "Dimensionality: " << solver.dim << std::endl; - std::cout << "Target UB Norm for index " << index << ": " << target << std::endl; + std::cout << "Target UB Norm for index " << index << ": " << target + << std::endl; NT norm; auto start = std::chrono::high_resolution_clock::now(); for (int i = 0; i < num_steps; i++) { solver.step(i, true); - #ifdef VOLESTI_DEBUG - solver.print_state(); - #endif +#ifdef VOLESTI_DEBUG + solver.print_state(); +#endif norm = sqrt(solver.xs[index].dot(solver.xs[index])); CHECK(norm < target); } auto stop = std::chrono::high_resolution_clock::now(); - long ETA = (long) std::chrono::duration_cast(stop - start).count(); + long ETA = (long)std::chrono::duration_cast(stop - start).count(); std::cout << "ETA (us): " << ETA << std::endl << std::endl; } - -template -void test_euler(){ - typedef Cartesian Kernel; - typedef typename Kernel::Point Point; - typedef std::vector pts; - typedef HPolytope Hpolytope; - typedef std::vector bounds; - typedef IsotropicQuadraticFunctor::GradientFunctor func; - typedef IsotropicQuadraticFunctor::parameters func_params; - func_params params; - params.alpha = 1; - params.order = 1; - func F(params); - - Point q0 = Point::all_ones(100); - - pts q; - q.push_back(q0); - EulerODESolver euler_solver = +template void test_euler() { + typedef Cartesian Kernel; + typedef typename Kernel::Point Point; + typedef std::vector pts; + typedef HPolytope Hpolytope; + typedef std::vector bounds; + typedef IsotropicQuadraticFunctor::GradientFunctor func; + typedef IsotropicQuadraticFunctor::parameters func_params; + func_params params; + params.alpha = 1; + params.order = 1; + func F(params); + + Point q0 = Point::all_ones(100); + + pts q; + q.push_back(q0); + EulerODESolver euler_solver = EulerODESolver(0, 0.01, q, F, bounds{NULL}); - check_norm(euler_solver, 2000, NT(0)); + check_norm(euler_solver, 2000, NT(0)); +} +template +void check_norm_progress(Solver &solver, int num_steps, std::vector target, + NT tol = 1e-4) { + for (int t = 0; t < target.size(); t++) { +#ifndef VOLESTI_DEBUG + solver.steps(num_steps, true); +#else + for (int i = 0; i < num_steps; i++) { + solver.step(i, true); + solver.print_state(); + } +#endif + NT norm = NT(0); + for (unsigned int i = 0; i < solver.xs.size(); i++) { + norm += solver.xs[i].dot(solver.xs[i]); + } + + norm = sqrt(norm); + NT error = abs(norm - target[t]); + + if (target[t] != NT(0)) + error /= target[t]; + CHECK(error < tol); + if (error > tol) { + break; + } + } } -template -void test_richardson(){ - typedef Cartesian Kernel; - typedef typename Kernel::Point Point; - typedef std::vector pts; - typedef HPolytope Hpolytope; - typedef std::vector bounds; - typedef IsotropicQuadraticFunctor::GradientFunctor func; - typedef IsotropicQuadraticFunctor::parameters func_params; - func_params params; - params.order = 1; - params.alpha = 1; - func F(params); - - - Point q0 = Point::all_ones(100); - pts q; - q.push_back(q0); - RichardsonExtrapolationODESolver bs_solver = - RichardsonExtrapolationODESolver(0, 0.1, q, F, bounds{NULL}); - - check_norm(bs_solver, 1000, NT(0)); +template void test_implicit_midpoint() { + typedef Cartesian Kernel; + typedef typename Kernel::Point Point; + typedef std::vector pts; + typedef GaussianFunctor::GradientFunctor grad; + typedef GaussianFunctor::FunctionFunctor func; + typedef GaussianFunctor::parameters func_params; + typedef opts Opts; + typedef crhmc_input Input; + typedef crhmc_problem CrhmcProblem; + typedef HPolytope Hpolytope; + unsigned d = 1; + Opts opts; + Point mean = Point(d); + func_params params = func_params(mean, 0.5, 1); + grad F(params); + func f(params); + Input input = Input(d, f, F); + input.lb = -VT::Ones(d); + input.ub = VT::Ones(d); + CrhmcProblem P = CrhmcProblem(input); + d = P.dimension(); + Point x0 = Point(d); + Point v0 = Point::all_ones(d); + pts q{x0, v0}; + opts.solver_accuracy_threshold = 1e-2; + opts.DynamicWeight = false; + ImplicitMidpointODESolver + implicit_midpoint_solver = + ImplicitMidpointODESolver(0, 0.01, q, + F, P, opts); + std::ifstream is("../test/test_norm_hypercube.txt"); + std::istream_iterator start(is), end; + std::vector target_norms(start, end); + check_norm_progress(implicit_midpoint_solver, 1, target_norms); +} +template void test_richardson() { + typedef Cartesian Kernel; + typedef typename Kernel::Point Point; + typedef std::vector pts; + typedef HPolytope Hpolytope; + typedef std::vector bounds; + typedef IsotropicQuadraticFunctor::GradientFunctor func; + typedef IsotropicQuadraticFunctor::parameters func_params; + func_params params; + params.order = 1; + params.alpha = 1; + func F(params); + + Point q0 = Point::all_ones(100); + pts q; + q.push_back(q0); + RichardsonExtrapolationODESolver bs_solver = + RichardsonExtrapolationODESolver( + 0, 0.1, q, F, bounds{NULL}); + + check_norm(bs_solver, 1000, NT(0)); } -template -void test_rk4(){ - typedef Cartesian Kernel; - typedef typename Kernel::Point Point; - typedef std::vector pts; - typedef HPolytope Hpolytope; - typedef std::vector bounds; - - typedef IsotropicQuadraticFunctor::GradientFunctor func; - typedef IsotropicQuadraticFunctor::parameters func_params; - func_params params; - params.alpha = 1; - params.order = 1; - func F(params); - - - Point q0 = Point::all_ones(100); - pts q; - q.push_back(q0); - RKODESolver rk_solver = +template void test_rk4() { + typedef Cartesian Kernel; + typedef typename Kernel::Point Point; + typedef std::vector pts; + typedef HPolytope Hpolytope; + typedef std::vector bounds; + + typedef IsotropicQuadraticFunctor::GradientFunctor func; + typedef IsotropicQuadraticFunctor::parameters func_params; + func_params params; + params.alpha = 1; + params.order = 1; + func F(params); + + Point q0 = Point::all_ones(100); + pts q; + q.push_back(q0); + RKODESolver rk_solver = RKODESolver(0, 0.1, q, F, bounds{NULL}); - rk_solver.steps(1000, true); - - check_norm(rk_solver, 1000, NT(0)); + rk_solver.steps(1000, true); + check_norm(rk_solver, 1000, NT(0)); } -template -void test_leapfrog_constrained(){ - typedef Cartesian Kernel; - typedef typename Kernel::Point Point; - typedef std::vector pts; - typedef HPolytope Hpolytope; - typedef std::vector bounds; - typedef IsotropicQuadraticFunctor::GradientFunctor func; - unsigned int dim = 1; - - IsotropicQuadraticFunctor::parameters params; - params.order = 2; - params.alpha = NT(1); - - func F(params); - - // Solve in P x R for - Hpolytope P = generate_cube(dim, false); - bounds Ks{&P, NULL}; - - Point x0 = Point(dim); - Point v0 = Point::all_ones(dim); - pts q{x0, v0}; - LeapfrogODESolver leapfrog_solver = +template void test_leapfrog_constrained() { + typedef Cartesian Kernel; + typedef typename Kernel::Point Point; + typedef std::vector pts; + typedef HPolytope Hpolytope; + typedef std::vector bounds; + typedef IsotropicQuadraticFunctor::GradientFunctor func; + unsigned int dim = 1; + + IsotropicQuadraticFunctor::parameters params; + params.order = 2; + params.alpha = NT(1); + + func F(params); + + // Solve in P x R for + Hpolytope P = generate_cube(dim, false); + bounds Ks{&P, NULL}; + + Point x0 = Point(dim); + Point v0 = Point::all_ones(dim); + pts q{x0, v0}; + LeapfrogODESolver leapfrog_solver = LeapfrogODESolver(0, 0.01, q, F, Ks); - check_index_norm_ub(leapfrog_solver, 1000, 0, 1.1 * sqrt(dim)); + check_index_norm_ub(leapfrog_solver, 1000, 0, 1.1 * sqrt(dim)); } +template void test_leapfrog() { + typedef Cartesian Kernel; + typedef typename Kernel::Point Point; + typedef std::vector pts; + typedef HPolytope Hpolytope; + typedef std::vector bounds; + IsotropicQuadraticFunctor::parameters params; + params.order = 2; + unsigned int dim = 3; -template -void test_leapfrog(){ - typedef Cartesian Kernel; - typedef typename Kernel::Point Point; - typedef std::vector pts; - typedef HPolytope Hpolytope; - typedef std::vector bounds; - IsotropicQuadraticFunctor::parameters params; - params.order = 2; - unsigned int dim = 3; + typedef IsotropicQuadraticFunctor::GradientFunctor func; + func F(params); - typedef IsotropicQuadraticFunctor::GradientFunctor func; - func F(params); + Point x0(dim); + Point v0 = Point::all_ones(dim); - Point x0(dim); - Point v0 = Point::all_ones(dim); + LeapfrogODESolver leapfrog_solver = + LeapfrogODESolver(0, 0.01, pts{x0, v0}, F, + bounds{NULL, NULL}); - LeapfrogODESolver leapfrog_solver = - LeapfrogODESolver(0, 0.01, pts{x0, v0}, F, bounds{NULL, NULL}); - - check_index_norm_ub(leapfrog_solver, 1000, 0, 1.1 * sqrt(dim)); + check_index_norm_ub(leapfrog_solver, 1000, 0, 1.1 * sqrt(dim)); } -template -void test_euler_constrained(){ - typedef Cartesian Kernel; - typedef typename Kernel::Point Point; - typedef std::vector pts; - typedef HPolytope Hpolytope; - typedef std::vector bounds; - typedef IsotropicQuadraticFunctor::GradientFunctor func; - IsotropicQuadraticFunctor::parameters params; - params.order = 2; - - typedef IsotropicQuadraticFunctor::GradientFunctor func; - func F(params); +template void test_euler_constrained() { + typedef Cartesian Kernel; + typedef typename Kernel::Point Point; + typedef std::vector pts; + typedef HPolytope Hpolytope; + typedef std::vector bounds; + typedef IsotropicQuadraticFunctor::GradientFunctor func; + IsotropicQuadraticFunctor::parameters params; + params.order = 2; - unsigned int dim = 1; + typedef IsotropicQuadraticFunctor::GradientFunctor func; + func F(params); - Hpolytope P = generate_cube(dim, false); - Point x0(dim); - Point v0 = Point::all_ones(dim); + unsigned int dim = 1; - EulerODESolver euler_solver = - EulerODESolver(0, 0.01, pts{x0, v0}, F, bounds{&P, NULL}); + Hpolytope P = generate_cube(dim, false); + Point x0(dim); + Point v0 = Point::all_ones(dim); - for (int i = 0; i < 1000; i++) { - euler_solver.step(i, true); - // CHECK(euler_solver.xs[0].dot(euler_solver.xs[0]) < 1.1 * dim); - } + EulerODESolver euler_solver = + EulerODESolver(0, 0.01, pts{x0, v0}, F, + bounds{&P, NULL}); + for (int i = 0; i < 1000; i++) { + euler_solver.step(i, true); + // CHECK(euler_solver.xs[0].dot(euler_solver.xs[0]) < 1.1 * dim); + } } -template -void test_richardson_constrained(){ - typedef Cartesian Kernel; - typedef typename Kernel::Point Point; - typedef std::vector pts; - typedef HPolytope Hpolytope; - typedef std::vector bounds; - typedef IsotropicQuadraticFunctor::GradientFunctor func; - IsotropicQuadraticFunctor::parameters params; - unsigned int dim = 4; - params.order = 2; - func F(params); - - Hpolytope P = generate_cube(dim, false); - - Point x0(dim); - Point v0 = Point::all_ones(dim); - - RichardsonExtrapolationODESolver r_solver = - RichardsonExtrapolationODESolver - (0, 0.01, pts{x0, v0}, F, bounds{&P, NULL}); - - check_index_norm_ub(r_solver, 1000, 0, 1.1 * sqrt(dim)); +template void test_richardson_constrained() { + typedef Cartesian Kernel; + typedef typename Kernel::Point Point; + typedef std::vector pts; + typedef HPolytope Hpolytope; + typedef std::vector bounds; + typedef IsotropicQuadraticFunctor::GradientFunctor func; + IsotropicQuadraticFunctor::parameters params; + unsigned int dim = 4; + params.order = 2; + func F(params); + + Hpolytope P = generate_cube(dim, false); + + Point x0(dim); + Point v0 = Point::all_ones(dim); + + RichardsonExtrapolationODESolver r_solver = + RichardsonExtrapolationODESolver( + 0, 0.01, pts{x0, v0}, F, bounds{&P, NULL}); + + check_index_norm_ub(r_solver, 1000, 0, 1.1 * sqrt(dim)); } -template -void test_rk4_constrained(){ - typedef Cartesian Kernel; - typedef typename Kernel::Point Point; - typedef std::vector pts; - typedef HPolytope Hpolytope; - typedef std::vector bounds; - typedef IsotropicQuadraticFunctor::GradientFunctor func; - IsotropicQuadraticFunctor::parameters params; - params.alpha = NT(-1); - params.order = 1; - func F(params); - - Point x0 = 0.5 * Point::all_ones(1); - - Hpolytope P = generate_cube(1, false); - - bounds Ks{&P}; - RKODESolver rk_solver = +template void test_rk4_constrained() { + typedef Cartesian Kernel; + typedef typename Kernel::Point Point; + typedef std::vector pts; + typedef HPolytope Hpolytope; + typedef std::vector bounds; + typedef IsotropicQuadraticFunctor::GradientFunctor func; + IsotropicQuadraticFunctor::parameters params; + params.alpha = NT(-1); + params.order = 1; + func F(params); + + Point x0 = 0.5 * Point::all_ones(1); + + Hpolytope P = generate_cube(1, false); + + bounds Ks{&P}; + RKODESolver rk_solver = RKODESolver(0, 0.01, pts{x0}, F, Ks); - check_norm(rk_solver, 1000, NT(1), 1e-2); + check_norm(rk_solver, 1000, NT(1), 1e-2); } -template -void call_test_first_order() { +template void call_test_first_order() { std::cout << "--- Testing solution to dx / dt = -x" << std::endl; test_euler(); @@ -316,163 +373,155 @@ void call_test_first_order() { std::cout << "--- Testing solution to dx / dt = x in [-1, 1]" << std::endl; test_rk4_constrained(); + std::cout << "--- Testing hamiltonian solution to f(x)=-x^2/2 in [-1, 1]" + << std::endl; + test_implicit_midpoint(); } -template -void call_test_second_order() { +template void call_test_second_order() { std::cout << "--- Testing solution to d^2x / dt^2 = -x" << std::endl; test_leapfrog(); // test_euler_constrained(); test_leapfrog_constrained(); } -TEST_CASE("first_order") { - call_test_first_order(); -} +TEST_CASE("first_order") { call_test_first_order(); } -TEST_CASE("second_order") { - call_test_second_order(); -} +TEST_CASE("second_order") { call_test_second_order(); } #ifndef DISABLE_NLP_ORACLES -template -void test_collocation(){ - typedef Cartesian Kernel; - typedef typename Kernel::Point Point; - typedef std::vector pts; - - typedef PolynomialBasis bfunc; - typedef std::vector coeffs; - typedef HPolytope Hpolytope; - typedef std::vector bounds; - typedef IsotropicQuadraticFunctor::GradientFunctor func; - typedef IsotropicQuadraticFunctor::parameters func_params; - func_params params; - params.order = 1; - params.alpha = 1; - func F(params); - - unsigned int dim = 5; - Point x0 = Point::all_ones(dim); - - bfunc phi(FUNCTION); - bfunc grad_phi(DERIVATIVE); - - // Trapezoidal collocation - coeffs cs{0.0, 0.0, 1.0}; - CollocationODESolver c_solver = - CollocationODESolver - (0, 1.0, pts{x0}, F, bounds{NULL}, cs, phi, grad_phi); - - check_norm(c_solver, 1000, NT(0)); +template void test_collocation() { + typedef Cartesian Kernel; + typedef typename Kernel::Point Point; + typedef std::vector pts; + + typedef PolynomialBasis bfunc; + typedef std::vector coeffs; + typedef HPolytope Hpolytope; + typedef std::vector bounds; + typedef IsotropicQuadraticFunctor::GradientFunctor func; + typedef IsotropicQuadraticFunctor::parameters func_params; + func_params params; + params.order = 1; + params.alpha = 1; + func F(params); + + unsigned int dim = 5; + Point x0 = Point::all_ones(dim); + + bfunc phi(FUNCTION); + bfunc grad_phi(DERIVATIVE); + + // Trapezoidal collocation + coeffs cs{0.0, 0.0, 1.0}; + CollocationODESolver c_solver = + CollocationODESolver( + 0, 1.0, pts{x0}, F, bounds{NULL}, cs, phi, grad_phi); + + check_norm(c_solver, 1000, NT(0)); } -template -void test_integral_collocation(){ - typedef Cartesian Kernel; - typedef typename Kernel::Point Point; - typedef std::vector pts; - - typedef std::vector coeffs; - - typedef HPolytope Hpolytope; - typedef std::vector bounds; - typedef IsotropicQuadraticFunctor::GradientFunctor func; - typedef IsotropicQuadraticFunctor::parameters func_params; - func_params params; - params.order = 1; - params.alpha = 1; - func F(params); - unsigned int dim = 3; - - Point x0 = Point::all_ones(dim); - IntegralCollocationODESolver c_solver = - IntegralCollocationODESolver - (0, 0.01, pts{x0}, F, bounds{NULL}, 8); - - check_norm(c_solver, 1000, NT(0)); +template void test_integral_collocation() { + typedef Cartesian Kernel; + typedef typename Kernel::Point Point; + typedef std::vector pts; + + typedef std::vector coeffs; + + typedef HPolytope Hpolytope; + typedef std::vector bounds; + typedef IsotropicQuadraticFunctor::GradientFunctor func; + typedef IsotropicQuadraticFunctor::parameters func_params; + func_params params; + params.order = 1; + params.alpha = 1; + func F(params); + unsigned int dim = 3; + + Point x0 = Point::all_ones(dim); + IntegralCollocationODESolver c_solver = + IntegralCollocationODESolver( + 0, 0.01, pts{x0}, F, bounds{NULL}, 8); + + check_norm(c_solver, 1000, NT(0)); } -template -void test_integral_collocation_constrained(){ - typedef Cartesian Kernel; - typedef typename Kernel::Point Point; - typedef std::vector pts; +template void test_integral_collocation_constrained() { + typedef Cartesian Kernel; + typedef typename Kernel::Point Point; + typedef std::vector pts; - typedef std::vector coeffs; + typedef std::vector coeffs; - typedef HPolytope Hpolytope; - typedef std::vector bounds; - typedef IsotropicQuadraticFunctor::GradientFunctor func; - typedef IsotropicQuadraticFunctor::parameters func_params; - func_params params; - params.order = 1; - params.alpha = -1; - func F(params); - unsigned int dim = 3; + typedef HPolytope Hpolytope; + typedef std::vector bounds; + typedef IsotropicQuadraticFunctor::GradientFunctor func; + typedef IsotropicQuadraticFunctor::parameters func_params; + func_params params; + params.order = 1; + params.alpha = -1; + func F(params); + unsigned int dim = 3; - Hpolytope K = generate_cube(dim, false); + Hpolytope K = generate_cube(dim, false); - Point x0 = Point::all_ones(dim); - IntegralCollocationODESolver c_solver = - IntegralCollocationODESolver - (0, 0.01, pts{x0}, F, bounds{&K}, 8); + Point x0 = Point::all_ones(dim); + IntegralCollocationODESolver c_solver = + IntegralCollocationODESolver( + 0, 0.01, pts{x0}, F, bounds{&K}, 8); - // check_norm(c_solver, 1000, NT(0)); + // check_norm(c_solver, 1000, NT(0)); } -template -void test_collocation_constrained(){ - typedef Cartesian Kernel; - typedef typename Kernel::Point Point; - typedef std::vector pts; - typedef PolynomialBasis bfunc; - typedef std::vector coeffs; - typedef HPolytope Hpolytope; - typedef std::vector bounds; - typedef IsotropicQuadraticFunctor::GradientFunctor func; - IsotropicQuadraticFunctor::parameters params; - unsigned int dim = 4; - params.order = 2; - func F(params); - - Hpolytope P = generate_cube(dim, false); - - bfunc phi(FUNCTION); - bfunc grad_phi(DERIVATIVE); - - Point x0(dim); - Point v0 = Point::all_ones(dim); - - // Trapezoidal collocation - coeffs cs{0.0, 0.0, 1.0}; - - CollocationODESolver c_solver = - CollocationODESolver - (0, 0.05, pts{x0, v0}, F, bounds{&P, NULL}, cs, phi, grad_phi); - - // NT err=0.1; - // NT target = 1.0; - // NT error = std::abs((c_solver.xs[0].dot(c_solver.xs[0]) - target) / target); - // CHECK(error < err); +template void test_collocation_constrained() { + typedef Cartesian Kernel; + typedef typename Kernel::Point Point; + typedef std::vector pts; + typedef PolynomialBasis bfunc; + typedef std::vector coeffs; + typedef HPolytope Hpolytope; + typedef std::vector bounds; + typedef IsotropicQuadraticFunctor::GradientFunctor func; + IsotropicQuadraticFunctor::parameters params; + unsigned int dim = 4; + params.order = 2; + func F(params); + + Hpolytope P = generate_cube(dim, false); + + bfunc phi(FUNCTION); + bfunc grad_phi(DERIVATIVE); + + Point x0(dim); + Point v0 = Point::all_ones(dim); + + // Trapezoidal collocation + coeffs cs{0.0, 0.0, 1.0}; + + CollocationODESolver c_solver = + CollocationODESolver( + 0, 0.05, pts{x0, v0}, F, bounds{&P, NULL}, cs, phi, grad_phi); + + // NT err=0.1; + // NT target = 1.0; + // NT error = std::abs((c_solver.xs[0].dot(c_solver.xs[0]) - target) / + // target); CHECK(error < err); } -template -void call_test_collocation() { +template void call_test_collocation() { - std::cout << "--- Testing solution to dx / dt = -x w/ collocation" << std::endl; + std::cout << "--- Testing solution to dx / dt = -x w/ collocation" + << std::endl; test_collocation(); test_integral_collocation(); - std::cout << "--- Testing solution to dx / dt = x in [-1, 1] w/ collocation" << std::endl; + std::cout << "--- Testing solution to dx / dt = x in [-1, 1] w/ collocation" + << std::endl; test_collocation_constrained(); // test_integral_collocation_constrained(); - } -TEST_CASE("collocation") { - call_test_collocation(); -} +TEST_CASE("collocation") { call_test_collocation(); } #endif diff --git a/test/test_norm_hypercube.txt b/test/test_norm_hypercube.txt new file mode 100644 index 000000000..2f6e8791f --- /dev/null +++ b/test/test_norm_hypercube.txt @@ -0,0 +1,1000 @@ +0.99995 +0.9998 +0.99955 +0.9992 +0.99875 +0.9982 +0.99754 +0.99679 +0.99593 +0.99497 +0.99391 +0.99274 +0.99147 +0.99009 +0.98861 +0.98702 +0.98532 +0.98351 +0.98159 +0.97956 +0.97741 +0.97516 +0.97279 +0.9703 +0.9677 +0.96498 +0.96214 +0.95918 +0.9561 +0.95289 +0.94956 +0.94611 +0.94253 +0.93883 +0.935 +0.93104 +0.92695 +0.92273 +0.91838 +0.91389 +0.90928 +0.90453 +0.89965 +0.89463 +0.88948 +0.88419 +0.87877 +0.87321 +0.86752 +0.86169 +0.85573 +0.84964 +0.84341 +0.83704 +0.83054 +0.82391 +0.81715 +0.81026 +0.80324 +0.7961 +0.78882 +0.78143 +0.7739 +0.76626 +0.7585 +0.75063 +0.74264 +0.73454 +0.72634 +0.71802 +0.70961 +0.7011 +0.6925 +0.68381 +0.67503 +0.66617 +0.65724 +0.64823 +0.63917 +0.63004 +0.62086 +0.61164 +0.60238 +0.59308 +0.58377 +0.57444 +0.5651 +0.55577 +0.54645 +0.53715 +0.5279 +0.51868 +0.50953 +0.50045 +0.49146 +0.48257 +0.4738 +0.46516 +0.45667 +0.44835 +0.44022 +0.43229 +0.4246 +0.41715 +0.40998 +0.4031 +0.39653 +0.39031 +0.38446 +0.37899 +0.37393 +0.36931 +0.36514 +0.36146 +0.35826 +0.35559 +0.35343 +0.35182 +0.35076 +0.35025 +0.35031 +0.35092 +0.35208 +0.35379 +0.35604 +0.35882 +0.3621 +0.36588 +0.37013 +0.37484 +0.37997 +0.38551 +0.39144 +0.39773 +0.40435 +0.41129 +0.41851 +0.42601 +0.43375 +0.44171 +0.44988 +0.45823 +0.46675 +0.47541 +0.48421 +0.49312 +0.50213 +0.51122 +0.52039 +0.52961 +0.53887 +0.54817 +0.5575 +0.56683 +0.57617 +0.58549 +0.59481 +0.6041 +0.61335 +0.62257 +0.63174 +0.64085 +0.64991 +0.6589 +0.66782 +0.67666 +0.68542 +0.6941 +0.70269 +0.71118 +0.71957 +0.72786 +0.73605 +0.74413 +0.7521 +0.75995 +0.76769 +0.77531 +0.78281 +0.79018 +0.79743 +0.80455 +0.81155 +0.81842 +0.82515 +0.83176 +0.83823 +0.84457 +0.85078 +0.85685 +0.86278 +0.86859 +0.87425 +0.87978 +0.88518 +0.89044 +0.89557 +0.90056 +0.90542 +0.91014 +0.91473 +0.91919 +0.92352 +0.92772 +0.93178 +0.93572 +0.93953 +0.94321 +0.94676 +0.95019 +0.9535 +0.95668 +0.95974 +0.96267 +0.96549 +0.96819 +0.97077 +0.97324 +0.97559 +0.97782 +0.97994 +0.98195 +0.98385 +0.98564 +0.98732 +0.98889 +0.99035 +0.99171 +0.99297 +0.99411 +0.99516 +0.9961 +0.99694 +0.99767 +0.99831 +0.99884 +0.99927 +0.9996 +0.99984 +0.99997 +1 +0.99993 +0.99976 +0.99949 +0.99912 +0.99865 +0.99808 +0.99741 +0.99664 +0.99576 +0.99478 +0.9937 +0.99251 +0.99122 +0.98982 +0.98832 +0.98671 +0.98499 +0.98316 +0.98122 +0.97917 +0.97701 +0.97473 +0.97234 +0.96983 +0.9672 +0.96446 +0.9616 +0.95862 +0.95551 +0.95228 +0.94893 +0.94546 +0.94186 +0.93813 +0.93427 +0.93029 +0.92618 +0.92193 +0.91756 +0.91305 +0.90841 +0.90363 +0.89873 +0.89368 +0.88851 +0.8832 +0.87775 +0.87217 +0.86645 +0.8606 +0.85461 +0.84849 +0.84224 +0.83585 +0.82933 +0.82267 +0.81589 +0.80897 +0.80193 +0.79476 +0.78746 +0.78004 +0.7725 +0.76484 +0.75705 +0.74916 +0.74115 +0.73303 +0.7248 +0.71647 +0.70804 +0.69951 +0.69089 +0.68219 +0.67339 +0.66452 +0.65557 +0.64656 +0.63748 +0.62834 +0.61916 +0.60992 +0.60066 +0.59136 +0.58204 +0.57271 +0.56337 +0.55404 +0.54472 +0.53544 +0.52618 +0.51698 +0.50784 +0.49878 +0.48981 +0.48094 +0.47219 +0.46357 +0.45511 +0.44683 +0.43873 +0.43085 +0.4232 +0.4158 +0.40868 +0.40186 +0.39535 +0.3892 +0.38341 +0.37802 +0.37304 +0.3685 +0.36442 +0.36083 +0.35773 +0.35515 +0.35309 +0.35158 +0.35062 +0.35022 +0.35038 +0.35109 +0.35236 +0.35417 +0.35652 +0.35939 +0.36277 +0.36663 +0.37097 +0.37576 +0.38097 +0.38658 +0.39258 +0.39893 +0.40561 +0.4126 +0.41988 +0.42742 +0.43521 +0.44321 +0.45141 +0.4598 +0.46834 +0.47704 +0.48585 +0.49478 +0.50381 +0.51292 +0.52209 +0.53132 +0.5406 +0.5499 +0.55923 +0.56856 +0.5779 +0.58722 +0.59653 +0.60581 +0.61506 +0.62427 +0.63343 +0.64253 +0.65158 +0.66056 +0.66946 +0.67829 +0.68704 +0.6957 +0.70427 +0.71274 +0.72112 +0.72939 +0.73756 +0.74562 +0.75356 +0.7614 +0.76911 +0.77671 +0.78418 +0.79153 +0.79876 +0.80586 +0.81283 +0.81968 +0.82639 +0.83297 +0.83942 +0.84573 +0.85191 +0.85796 +0.86387 +0.86965 +0.87529 +0.88079 +0.88617 +0.8914 +0.8965 +0.90147 +0.9063 +0.911 +0.91557 +0.92001 +0.92431 +0.92848 +0.93252 +0.93643 +0.94022 +0.94388 +0.94741 +0.95081 +0.95409 +0.95725 +0.96029 +0.9632 +0.966 +0.96868 +0.97124 +0.97368 +0.97601 +0.97822 +0.98032 +0.98231 +0.98419 +0.98596 +0.98762 +0.98917 +0.99061 +0.99195 +0.99319 +0.99431 +0.99534 +0.99626 +0.99708 +0.9978 +0.99841 +0.99893 +0.99934 +0.99965 +0.99987 +0.99998 +0.99999 +0.99991 +0.99972 +0.99943 +0.99904 +0.99856 +0.99797 +0.99728 +0.99648 +0.99559 +0.99459 +0.99349 +0.99228 +0.99097 +0.98955 +0.98803 +0.9864 +0.98466 +0.98281 +0.98085 +0.97878 +0.97659 +0.97429 +0.97188 +0.96935 +0.9667 +0.96394 +0.96105 +0.95805 +0.95492 +0.95167 +0.9483 +0.9448 +0.94118 +0.93743 +0.93355 +0.92954 +0.9254 +0.92113 +0.91673 +0.9122 +0.90753 +0.90273 +0.8978 +0.89273 +0.88753 +0.8822 +0.87673 +0.87112 +0.86538 +0.8595 +0.85349 +0.84734 +0.84106 +0.83465 +0.8281 +0.82142 +0.81461 +0.80768 +0.80061 +0.79342 +0.7861 +0.77865 +0.77109 +0.7634 +0.7556 +0.74768 +0.73965 +0.73151 +0.72327 +0.71492 +0.70647 +0.69792 +0.68929 +0.68056 +0.67175 +0.66287 +0.65391 +0.64488 +0.63579 +0.62664 +0.61745 +0.60821 +0.59893 +0.58963 +0.58031 +0.57098 +0.56164 +0.55231 +0.543 +0.53372 +0.52447 +0.51528 +0.50616 +0.49711 +0.48815 +0.4793 +0.47058 +0.46199 +0.45357 +0.44531 +0.43726 +0.42941 +0.42181 +0.41446 +0.40739 +0.40063 +0.39419 +0.3881 +0.38238 +0.37706 +0.37217 +0.36771 +0.36372 +0.36021 +0.35721 +0.35473 +0.35277 +0.35136 +0.35051 +0.35021 +0.35047 +0.35128 +0.35265 +0.35456 +0.35701 +0.35998 +0.36345 +0.3674 +0.37182 +0.37669 +0.38198 +0.38767 +0.39373 +0.40014 +0.40688 +0.41393 +0.42126 +0.42885 +0.43667 +0.44472 +0.45295 +0.46137 +0.46994 +0.47866 +0.4875 +0.49645 +0.50549 +0.51461 +0.5238 +0.53304 +0.54232 +0.55163 +0.56096 +0.57029 +0.57963 +0.58895 +0.59825 +0.60753 +0.61677 +0.62597 +0.63512 +0.64422 +0.65325 +0.66221 +0.67111 +0.67992 +0.68865 +0.69729 +0.70585 +0.7143 +0.72266 +0.73091 +0.73906 +0.7471 +0.75502 +0.76283 +0.77053 +0.7781 +0.78555 +0.79288 +0.80009 +0.80716 +0.81411 +0.82093 +0.82762 +0.83417 +0.8406 +0.84689 +0.85304 +0.85906 +0.86495 +0.8707 +0.87632 +0.8818 +0.88715 +0.89236 +0.89743 +0.90238 +0.90719 +0.91186 +0.9164 +0.92081 +0.92509 +0.92924 +0.93326 +0.93715 +0.94091 +0.94454 +0.94805 +0.95143 +0.95469 +0.95782 +0.96084 +0.96373 +0.96651 +0.96916 +0.9717 +0.97412 +0.97643 +0.97862 +0.9807 +0.98267 +0.98453 +0.98628 +0.98791 +0.98945 +0.99087 +0.99219 +0.9934 +0.99451 +0.99552 +0.99642 +0.99722 +0.99792 +0.99852 +0.99901 +0.99941 +0.9997 +0.9999 +0.99999 +0.99998 +0.99988 +0.99967 +0.99937 +0.99896 +0.99845 +0.99785 +0.99714 +0.99632 +0.99541 +0.99439 +0.99327 +0.99205 +0.99072 +0.98928 +0.98774 +0.98608 +0.98432 +0.98245 +0.98047 +0.97838 +0.97617 +0.97386 +0.97142 +0.96887 +0.9662 +0.96341 +0.96051 +0.95748 +0.95433 +0.95106 +0.94766 +0.94414 +0.94049 +0.93672 +0.93281 +0.92878 +0.92462 +0.92033 +0.9159 +0.91134 +0.90665 +0.90183 +0.89687 +0.89178 +0.88655 +0.88119 +0.8757 +0.87006 +0.8643 +0.8584 +0.85236 +0.84619 +0.83988 +0.83345 +0.82687 +0.82017 +0.81334 +0.80638 +0.79929 +0.79207 +0.78473 +0.77726 +0.76967 +0.76196 +0.75414 +0.7462 +0.73815 +0.72999 +0.72173 +0.71336 +0.70489 +0.69633 +0.68768 +0.67894 +0.67011 +0.66121 +0.65224 +0.6432 +0.6341 +0.62494 +0.61574 +0.60649 +0.59721 +0.58791 +0.57858 +0.56925 +0.55991 +0.55058 +0.54128 +0.532 +0.52277 +0.51359 +0.50447 +0.49544 +0.4865 +0.47768 +0.46898 +0.46042 +0.45202 +0.4438 +0.43579 +0.42799 +0.42043 +0.41313 +0.40611 +0.39941 +0.39303 +0.38701 +0.38137 +0.37612 +0.37131 +0.36694 +0.36303 +0.35962 +0.35671 +0.35432 +0.35247 +0.35116 +0.35041 +0.35021 +0.35058 +0.3515 +0.35297 +0.35498 +0.35752 +0.36058 +0.36414 +0.36819 +0.37269 +0.37764 +0.383 +0.38876 +0.39489 +0.40137 +0.40817 +0.41527 +0.42265 +0.43028 +0.43815 +0.44623 +0.4545 +0.46295 +0.47155 +0.48029 +0.48915 +0.49812 +0.50718 +0.51631 +0.52551 +0.53476 +0.54404 +0.55336 +0.56269 +0.57202 +0.58135 +0.59068 +0.59998 +0.60925 +0.61848 +0.62767 +0.63681 +0.64589 +0.65492 +0.66387 +0.67275 +0.68154 +0.69026 +0.69889 +0.70742 +0.71586 +0.7242 +0.73243 +0.74056 +0.74857 +0.75648 +0.76427 +0.77194 +0.77949 +0.78692 +0.79423 +0.80141 +0.80846 +0.81538 +0.82218 +0.82884 +0.83537 +0.84177 +0.84804 +0.85417 +0.86017 +0.86603 +0.87175 +0.87735 +0.8828 +0.88812 +0.89331 +0.89836 +0.90328 +0.90806 +0.91271 +0.91723 +0.92162 +0.92587 +0.92999 +0.93399 +0.93785 +0.94159 +0.9452 +0.94868 +0.95204 +0.95528 +0.95839 +0.96138 +0.96426 +0.96701 +0.96964 +0.97216 +0.97456 +0.97684 +0.97901 +0.98107 +0.98302 +0.98486 +0.98659 +0.98821 +0.98972 +0.99112 +0.99242 +0.99362 +0.99471 +0.99569 +0.99658 +0.99736 +0.99804 +0.99862 +0.99909 +0.99947 +0.99975 +0.99992 +1 +0.99997 +0.99985 +0.99962 +0.9993 +0.99888 +0.99835 +0.99772 +0.99699 +0.99616 +0.99523 +0.99419 +0.99305 +0.99181 +0.99046 +0.989 +0.98744 +0.98577 +0.98399 +0.9821 +0.98009 +0.97798 +0.97575 +0.97341 +0.97096 +0.96838 +0.96569 +0.96288 +0.95996 +0.95691 +0.95373 +0.95044 +0.94702 +0.94347 +0.9398 +0.936 +0.93208 +0.92802 From 130a2dff0dc03aaa0ec8eb114517d5b08efa5679 Mon Sep 17 00:00:00 2001 From: Huu Phuoc Le Date: Wed, 2 Nov 2022 11:26:48 +0100 Subject: [PATCH 11/20] Feature/sampling correlation matrices (#233) * first commit * draft * draft * update some code * finish Point_matrix.cpp * change name: CorreSpectra.cpp * update * TODO * change TODO * update * update * update * update * clean * update * correlation class * billiard walk * eigenvaluescorrelation.h * update * update * update * update * update * update * faster billiard walk * add missing CMake file * start hmc * add old sampler file * Revert "add old sampler file" This reverts commit 1b2f299de0979156f8cf598e93a0e22f431c5d0a. * Revert "start hmc" This reverts commit 642d4e1f1f7357c41a89a183817127aded161016. * revert commits of HMC walk * clean unecessary code and fix minor changes * New class CorreSpectra inherits from Spectrahedron * add first code of ReHMC with leap frog for Gaussian sampling for testing * relocate files: * sample_correlation_matrices.hpp -> sampling/ * test.hpp -> test/sampling_correlation_matrices_test.cpp * ReHMC.cpp -> random_walks/gaussian_ReHMC_correlation.hpp * move test files to test folder and add more test * change ReHMC code to WalkType class to suit volesti * move content of EigenvaluesCorrelation to EigenvaluesProblems remove temporary HCM walk change Walk Length of test to 1 * simplify code of corre_spectra.hpp * new correlation matrix class : CorreSpectra2 (testing: run for n=3, bug for n=10) * fix bugs of CorreSpectra2 for BilliardWalk * add some more tests + optimize reflection of CorreSpectra2 * fix some bugs of Spectrahedra to run BallWalk and AcceleratedBilliardWalk * New changes: * Change name of CorreSpectr2 -> CorreSpectra_MT * Added and tested BallWalk for CorreSpectra_MT * Compute diameter: remove NT(6) * Remove commented code * remove redundant comments * add examples for sampling correlation matrices and remove redundant functions in tests * added RDHR walk + fixed small changes * remove redundant files in examples * update CMakeLists in examples to enable MKL * change MKL linking in examples' CMakeLists.txt * change const specifier in several functions + readded const for Polytope arguments in functions of uniform_ball_walk.hpp * add const specifier to is_in in spectrahedron class (required for Ball Walk) * newline end of gitignore * add copyright to examples * format uniform_billiard_walk.hpp (indent, trailing spaces,...) * change header guards of convex_bodies correlation_matrices files * fix bugs in Spectrahedron line_intersect (wrong sign of negative distance) and change order of vector coefficients of CorreSpectra to lower triangular part (to homogenize with CorreSpectra_MT) * homogenize check_output in tests for CorreSpectra and CorreSpectra_MT * change names of CorreSpectra classes to CorrelationSpectrahedron * change include path of CorrelationSpectrahedron in random walks * format and optimize (minor) sampling/sphere.hpp * add Copyright headers * format style corre_matrix.hpp * format style CorrelationSpectrahedron * format style CorrelationSpectrahedron classes * move direct (old) sampling functions to examples and remove tests for those functions in test file * remove old tests from CMakeLists.txt * add const keywords back to RDHR Walk * fix bugs in corre_matrix * add const keyword back to gaussian random point generator Co-authored-by: phuoc Co-authored-by: Vissarion Fisikopoulos --- .gitignore | 1 + examples/correlation_matrices/.Rhistory | 0 examples/correlation_matrices/CMakeLists.txt | 139 +++++++++ examples/correlation_matrices/README.md | 14 + examples/correlation_matrices/plot.py | 18 ++ examples/correlation_matrices/sampler.cpp | 170 +++++++++++ include/cartesian_geom/point.h | 12 +- .../correlation_matrices/corre_matrix.hpp | 162 +++++++++++ .../correlation_spectrahedron.hpp | 267 ++++++++++++++++++ .../correlation_spectrahedron_MT.hpp | 180 ++++++++++++ .../spectrahedra/spectrahedron.h | 39 ++- .../matrix_operations/EigenvaluesProblems.h | 35 ++- include/random_walks/compute_diameter.hpp | 22 ++ include/random_walks/random_walks.hpp | 2 + .../random_walks/uniform_billiard_walk.hpp | 18 +- .../sampling/sample_correlation_matrices.hpp | 153 ++++++++++ include/sampling/sphere.hpp | 71 ++++- test/CMakeLists.txt | 14 +- test/sampling_correlation_matrices_test.cpp | 207 ++++++++++++++ 19 files changed, 1485 insertions(+), 39 deletions(-) create mode 100644 examples/correlation_matrices/.Rhistory create mode 100644 examples/correlation_matrices/CMakeLists.txt create mode 100755 examples/correlation_matrices/README.md create mode 100644 examples/correlation_matrices/plot.py create mode 100644 examples/correlation_matrices/sampler.cpp create mode 100755 include/convex_bodies/correlation_matrices/corre_matrix.hpp create mode 100755 include/convex_bodies/correlation_matrices/correlation_spectrahedron.hpp create mode 100755 include/convex_bodies/correlation_matrices/correlation_spectrahedron_MT.hpp create mode 100644 include/sampling/sample_correlation_matrices.hpp create mode 100644 test/sampling_correlation_matrices_test.cpp diff --git a/.gitignore b/.gitignore index 91a9011fa..6976e6147 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ test/build external/_deps examples/build +.vscode test/Testing/Temporary/CTestCostData.txt *.log .Rproj.user diff --git a/examples/correlation_matrices/.Rhistory b/examples/correlation_matrices/.Rhistory new file mode 100644 index 000000000..e69de29bb diff --git a/examples/correlation_matrices/CMakeLists.txt b/examples/correlation_matrices/CMakeLists.txt new file mode 100644 index 000000000..7871ba5fa --- /dev/null +++ b/examples/correlation_matrices/CMakeLists.txt @@ -0,0 +1,139 @@ +# Licensed under GNU LGPL.3, see LICENCE file +# VolEsti (volume computation and sampling library) + +# Copyright (c) 2012-2021 Vissarion Fisikopoulos +# Copyright (c) 2018-2021 Apostolos Chalkis + +# Contributed and/or modified by Huu Phuoc Le + +# Licensed under GNU LGPL.3, see LICENCE file + +project( VolEsti ) + + +CMAKE_MINIMUM_REQUIRED(VERSION 3.11) + +set(MKLROOT /opt/intel/oneapi/mkl/latest) +message("MKLROOT = " ${MKLROOT}) +set(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS true) + +if(COMMAND cmake_policy) + cmake_policy(SET CMP0003 NEW) +endif(COMMAND cmake_policy) + + +option(DISABLE_NLP_ORACLES "Disable non-linear oracles (used in collocation)" ON) +option(BUILTIN_EIGEN "Use eigen from ../../external" OFF) +option(USE_MKL "Use MKL library to build eigen" OFF) + +if(DISABLE_NLP_ORACLES) + add_definitions(-DDISABLE_NLP_ORACLES) +else() + find_library(IFOPT NAMES libifopt_core.so PATHS /usr/local/lib) + find_library(IFOPT_IPOPT NAMES libifopt_ipopt.so PATHS /usr/local/lib) + find_library(GMP NAMES libgmp.so PATHS /usr/lib/x86_64-linux-gnu /usr/lib/i386-linux-gnu) + find_library(MPSOLVE NAMES libmps.so PATHS /usr/local/lib) + find_library(PTHREAD NAMES libpthread.so PATHS /usr/lib/x86_64-linux-gnu /usr/lib/i386-linux-gnu) + find_library(FFTW3 NAMES libfftw3.so.3 PATHS /usr/lib/x86_64-linux-gnu /usr/lib/i386-linux-gnu) + + if (NOT IFOPT) + + message(FATAL_ERROR "This program requires the ifopt library, and will not be compiled.") + + elseif (NOT GMP) + + message(FATAL_ERROR "This program requires the gmp library, and will not be compiled.") + + elseif (NOT MPSOLVE) + + message(FATAL_ERROR "This program requires the mpsolve library, and will not be compiled.") + + elseif (NOT FFTW3) + + message(FATAL_ERROR "This program requires the fftw3 library, and will not be compiled.") + + else() + message(STATUS "Library ifopt found: ${IFOPT}") + message(STATUS "Library gmp found: ${GMP}") + message(STATUS "Library mpsolve found: ${MPSOLVE}") + message(STATUS "Library fftw3 found:" ${FFTW3}) + + endif(NOT IFOPT) + +endif(DISABLE_NLP_ORACLES) + +include("../../external/cmake-files/Eigen.cmake") +GetEigen() + +include("../../external/cmake-files/Boost.cmake") +GetBoost() + +include("../../external/cmake-files/LPSolve.cmake") +GetLPSolve() + +if (BUILTIN_EIGEN) + include_directories (BEFORE ../../external/_deps/Eigen) +else () + include_directories(BEFORE /usr/include/eigen3) +endif(BUILTIN_EIGEN) + +if (USE_MKL) + find_library(BLAS NAME libblas.so + PATHS /usr/lib/x86_64-linux-gnu /usr/lib/i386-linux-gnu /usr/lib64/atlas /usr/lib/atlas /usr/lib64 /usr/lib /usr/local/lib64 /usr/local/lib + ) + message(STATUS "BLAS library found: ${BLAS}") + + message(STATUS "MKL library found: ${MKLROOT}") + include_directories (BEFORE ${MKLROOT}/include) + set(PROJECT_LIBS ${BLAS_LIBRARIES}) + add_definitions(-DEIGEN_USE_MKL_ALL) + + # Set linking for MKL : may affect performance + set(MKL_LINK "-L${MKLROOT}/lib/intel64 -Wl,-rpath,${MKLROOT}/lib -lmkl_intel_ilp64 -lmkl_sequential -lmkl_core -lgomp -lpthread -llapack -lblas") +endif(USE_MKL) + +# Find lpsolve library +find_library(LP_SOLVE NAMES liblpsolve55.so PATHS /usr/lib/lp_solve) + +if (NOT LP_SOLVE) + message(FATAL_ERROR "This program requires the lp_solve library, and will not be compiled.") +else () + message(STATUS "lp_solve library found: ${LP_SOLVE}") + + set(CMAKE_EXPORT_COMPILE_COMMANDS "ON") + + include_directories (BEFORE ../../external) + include_directories (BEFORE ../../external/minimum_ellipsoid) + include_directories (BEFORE ../../include/generators) + include_directories (BEFORE ../../include/volume) + include_directories (BEFORE ../../include) + include_directories (BEFORE ../../include/lp_oracles) + include_directories (BEFORE ../../include/nlp_oracles) + include_directories (BEFORE ../../include/convex_bodies) + include_directories (BEFORE ../../include/random_walks) + include_directories (BEFORE ../../include/annealing) + include_directories (BEFORE ../../include/ode_solvers) + include_directories (BEFORE ../../include/root_finders) + include_directories (BEFORE ../../include/samplers) + include_directories (BEFORE ../../include/misc) + include_directories (BEFORE ../../include/optimization) + + # for Eigen + if (${CMAKE_VERSION} VERSION_LESS "3.12.0") + add_compile_options(-D "EIGEN_NO_DEBUG") + else () + add_compile_definitions("EIGEN_NO_DEBUG") + endif () + + add_definitions(${CMAKE_CXX_FLAGS} "-std=c++11") # enable C++11 standard + add_definitions(${CMAKE_CXX_FLAGS} "-O3") # optimization of the compiler + #add_definitions(${CXX_COVERAGE_COMPILE_FLAGS} "-lgsl") + add_definitions(${CXX_COVERAGE_COMPILE_FLAGS} "-lm") + add_definitions(${CMAKE_CXX_FLAGS} "-DMKL_ILP64") + add_definitions(${CXX_COVERAGE_COMPILE_FLAGS} "-ldl") + add_definitions(${CXX_COVERAGE_COMPILE_FLAGS} "-DBOOST_NO_AUTO_PTR") + + add_executable (sampler sampler.cpp) + TARGET_LINK_LIBRARIES(sampler ${LP_SOLVE} ${BLAS} ${MKL_LINK}) + +endif() diff --git a/examples/correlation_matrices/README.md b/examples/correlation_matrices/README.md new file mode 100755 index 000000000..eac3e5e6b --- /dev/null +++ b/examples/correlation_matrices/README.md @@ -0,0 +1,14 @@ +## Compilation +Build the example by running the following commands in this directory. + +```bash +mkdir -p build && cd build +cmake . -DLP_SOLVE=_PATH_TO_LPSOLVE_LIB ../ && make +``` +You have to specify the path to liblpsolve55.so/dll/dylib. +For example: -DLP_SOLVE=/usr/lib/lpsolve/liblpsolve55.so + +## Usage: +```bash +./sampler && python3 ../plot.py +``` \ No newline at end of file diff --git a/examples/correlation_matrices/plot.py b/examples/correlation_matrices/plot.py new file mode 100644 index 000000000..eaff4bd32 --- /dev/null +++ b/examples/correlation_matrices/plot.py @@ -0,0 +1,18 @@ +import numpy as np +import matplotlib.pyplot as plt +from mpl_toolkits.mplot3d import Axes3D + +# plot data +filenames = ["BallWalk_matrices.txt", "RDHRWalk_matrices.txt",\ + "BilliardWalk_matrices.txt", "AcceleratedBilliardWalk_matrices.txt",\ + "BallWalk_matrices_MT.txt", "RDHRWalk_matrices_MT.txt",\ + "BilliardWalk_matrices_MT.txt", "AcceleratedBilliardWalk_matrices_MT.txt"] +for filename in filenames: + fig = plt.figure(figsize=(4,4)) + ax = plt.axes(projection='3d') + data = np.genfromtxt(filename, delimiter=' ') + ax.scatter(data[:, 0], data[:, 1], data[:, 2], s = 1) + plt.title(filename) + +# show all plots +plt.show() diff --git a/examples/correlation_matrices/sampler.cpp b/examples/correlation_matrices/sampler.cpp new file mode 100644 index 000000000..9a2ac08d2 --- /dev/null +++ b/examples/correlation_matrices/sampler.cpp @@ -0,0 +1,170 @@ +// Licensed under GNU LGPL.3, see LICENCE file +// VolEsti (volume computation and sampling library) + +// Copyright (c) 2012-2021 Vissarion Fisikopoulos +// Copyright (c) 2018-2021 Apostolos Chalkis + +// Contributed by Huu Phuoc Le as part of Google Summer of Code 2022 program + +// Licensed under GNU LGPL.3, see LICENCE file + +#include +#include +#include +#include + +#include "cartesian_geom/cartesian_kernel.h" +#include "convex_bodies/spectrahedra/spectrahedron.h" +#include "random_walks/random_walks.hpp" +#include "sampling/sample_correlation_matrices.hpp" + +typedef double NT; +typedef Eigen::Matrix MT; +typedef Eigen::Matrix VT; + +typedef BoostRandomNumberGenerator RNGType; + +typedef Cartesian Kernel; +typedef typename Kernel::Point Point; +typedef CorreMatrix PointMT; + +// Direct call to sampling algorithms for Spectrahedron class for comparison + +std::vector LMIGen(int n){ + int i, j, l, k = n*(n-1)/2+1; + std::vector list_Mat; + MT A; + list_Mat.push_back(-MT::Identity(n, n)); + for(i = 0; i < n; ++i){ + for(j = 0; j < i; ++j){ + A = MT::Zero(n, n); + A(i,j) = -1; + A(j,i) = -1; + list_Mat.push_back(A); + } + } + return list_Mat; +} + +Spectrahedron prepare_input(int n){ + int d = n*(n-1)/2; + Point p(d); + std::vector lmi_mat = LMIGen(n); + LMI lmi(lmi_mat); + Spectrahedron spectra(lmi); + spectra.set_interior_point(p); + spectra._inner_ball.second = 1/std::sqrt(d); + return spectra; +} + +template +void old_uniform_sampling(const unsigned int n, const unsigned int num_points){ + + std::cout << "Old sampling : "<< num_points <<" uniform correlation matrices of size " << n << std::endl; + std::chrono::steady_clock::time_point start, end; + double time; + std::vector randPoints; + unsigned int walkL = 1; + + Spectrahedron spectra = prepare_input(n); + int d = spectra.dimension(); + Point p(d); + RNGType rng(d); + + start = std::chrono::steady_clock::now(); + + uniform_sampling(randPoints, spectra, rng, walkL, num_points, p, 0); + + end = std::chrono::steady_clock::now(); + time = std::chrono::duration_cast(end - start).count(); + std::cout << "Elapsed time : " << time << " (ms)" << std::endl; +} + +template +void write_to_file(std::string filename, std::vector const& randPoints){ + std::ofstream out(filename); + auto coutbuf = std::cout.rdbuf(out.rdbuf()); + for(int i=0; i +void correlation_matrix_uniform_sampling(const unsigned int n, const unsigned int num_points, std::string walkname){ + + std::cout << walkname << " samples uniformly "<< num_points << " correlation matrices of size " << n << std::endl; + std::chrono::steady_clock::time_point start, end; + double time; + std::vector randPoints; + unsigned int walkL = 1; + + start = std::chrono::steady_clock::now(); + + uniform_correlation_sampling(n, randPoints, walkL, num_points, 0); + + end = std::chrono::steady_clock::now(); + time = std::chrono::duration_cast(end - start).count(); + std::cout << "Elapsed time : " << time << " (ms)" << std::endl; + + write_to_file(walkname + "_matrices.txt", randPoints); +} + +template +void correlation_matrix_uniform_sampling_MT(const unsigned int n, const unsigned int num_points, std::string walkname){ + + std::cout << walkname << " samples uniformly "<< num_points << " correlation matrices of size " << n << " with matrix PointType" << std::endl; + std::chrono::steady_clock::time_point start, end; + double time; + std::vector randPoints; + unsigned int walkL = 1; + + start = std::chrono::steady_clock::now(); + + uniform_correlation_sampling_MT(n, randPoints, walkL, num_points, 0); + + end = std::chrono::steady_clock::now(); + time = std::chrono::duration_cast(end - start).count(); + std::cout << "Elapsed time : " << time << " (ms)" << std::endl; + + write_to_file(walkname + "_matrices_MT.txt", randPoints); +} + +int main(int argc, char const *argv[]){ + +// To enable Intel MKL, change option USE_MKL to ON in CMakeLists.txt + +#ifdef EIGEN_USE_MKL_ALL + + MKLVersion Version; + + mkl_get_version(&Version); + + printf("Using Intel MKL %d.%d.%d\n",Version.MajorVersion,Version.MinorVersion,Version.UpdateVersion); + printf("Platform: %s\n",Version.Platform); + printf("Processor optimization: %s\n",Version.Processor); + printf("================================================================\n"); + printf("\n"); +#endif + + unsigned int n = 3, num_points = 5000; + + old_uniform_sampling(n, num_points); + + correlation_matrix_uniform_sampling(n, num_points, "BallWalk"); + + correlation_matrix_uniform_sampling(n, num_points, "RDHRWalk"); + + correlation_matrix_uniform_sampling(n, num_points, "BilliardWalk"); + + correlation_matrix_uniform_sampling(n, num_points, "AcceleratedBilliardWalk"); + + correlation_matrix_uniform_sampling_MT(n, num_points, "BallWalk"); + + correlation_matrix_uniform_sampling_MT(n, num_points, "RDHRWalk"); + + correlation_matrix_uniform_sampling_MT(n, num_points, "BilliardWalk"); + + correlation_matrix_uniform_sampling_MT(n, num_points, "AcceleratedBilliardWalk"); + + return 0; +} \ No newline at end of file diff --git a/include/cartesian_geom/point.h b/include/cartesian_geom/point.h index 64fd048fd..532404a0f 100644 --- a/include/cartesian_geom/point.h +++ b/include/cartesian_geom/point.h @@ -116,7 +116,17 @@ class point void operator+= (const Coeff& coeffs) { - this->coeffs = coeffs + this->coeffs; + this->coeffs += coeffs; + } + + void operator-= (const point& p) + { + coeffs -= p.getCoefficients(); + } + + void operator-= (const Coeff& coeffs) + { + this->coeffs -= coeffs; } void operator= (const Coeff& coeffs) diff --git a/include/convex_bodies/correlation_matrices/corre_matrix.hpp b/include/convex_bodies/correlation_matrices/corre_matrix.hpp new file mode 100755 index 000000000..d8d8142ad --- /dev/null +++ b/include/convex_bodies/correlation_matrices/corre_matrix.hpp @@ -0,0 +1,162 @@ +// VolEsti (volume computation and sampling library) + +// Copyright (c) 2012-2020 Vissarion Fisikopoulos +// Copyright (c) 2020 Apostolos Chalkis + +// Contributed by Huu Phuoc Le as part of Google Summer of Code 2022 program + +// Licensed under GNU LGPL.3, see LICENCE file + +#ifndef VOLESTI_CONVEX_BODIES_CORRELATION_MATRICES_CORRE_MATRIX_HPP +#define VOLESTI_CONVEX_BODIES_CORRELATION_MATRICES_CORRE_MATRIX_HPP + +/// This class handles the PointType used by CorreSpectra_MT class. +/// Every point is a correlation matrix and only the lower triangular part is stored. + +/// @tparam NT +template +class CorreMatrix{ + public: + + /// The numeric/matrix/vector types we use + typedef NT FT; + typedef Eigen::Matrix MT; + typedef Eigen::Matrix VT; + typedef Eigen::Matrix Coeff; + + MT mat; + + CorreMatrix(){} + + CorreMatrix(unsigned int n){ + mat = MT::Identity(n,n); + } + + CorreMatrix(MT const& mat){ + this->mat = mat; + } + + CorreMatrix(VT const& coeffs){ + unsigned int n = ceil(sqrt(2*coeffs.rows())); + this->mat = MT::Identity(n,n); + int ind = 0; + for(int i = 0; i < n; ++i){ + for(int j = 0; j < i; ++j){ + this->mat(i,j) = coeffs(ind); + ++ind; + } + } + } + + int dimension() const { + int n = this->mat.rows(); + return n*(n-1)/2; + } + + void operator+= (const CorreMatrix & p){ + this->mat += p.mat; + } + + void operator-= (const CorreMatrix & p){ + this->mat -= p.mat; + } + + void operator= (const CorreMatrix & p){ + this->mat = p.mat; + } + + CorreMatrix operator+ (const CorreMatrix& p) const { + CorreMatrix temp; + temp.mat = this->mat + p.mat; + return temp; + } + + + CorreMatrix operator- () const { + CorreMatrix temp; + temp.mat = - this->mat; + return temp; + } + + void operator*= (const FT k){ + this->mat *= k; + } + + CorreMatrix operator* (const FT k) const { + MT M = this->mat; + M *= k; + return CorreMatrix(M); + } + + void operator/= (const FT k){ + this->mat /= k; + } + + NT dot(MT grad){ + int i, j, n = this->mat.rows(); + NT ret = NT(0); + for(i = 0; i < n ; ++i){ + for(j = 0; j < i; ++j){ + ret += this->mat(i,j) * grad(i,j); + } + } + return ret; + } + + NT dot(CorreMatrix c){ + int i, j, n = this->mat.rows(); + NT ret = NT(0); + for(i = 0; i < n ; ++i){ + for(j = 0; j < i; ++j){ + ret += this->mat(i,j) * c.mat(i,j); + } + } + return ret; + } + + NT squared_length() const { + int i, j, n = this->mat.rows(); + NT ret = NT(0); + for(i = 0; i < n ; ++i){ + for(j = 0; j < i; ++j){ + ret += this->mat(i,j) * this->mat(i,j); + } + } + return ret; + } + + void print() const { + int n = this->mat.rows(), i, j; + for(i = 0; i < n ; ++i){ + for(j = 0; j < i; ++j){ + std::cout<< this->mat(i,j) <<" "; + } + } + std::cout<<"\n"; + } + + VT getCoefficients() const { + int n = this->mat.rows(), ind = 0, i, j; + VT coeff(n*(n-1)/2); + for(i = 0; i < n ; ++i){ + for(j = 0; j < i; ++j){ + coeff(ind) = this->mat(i,j); + ++ind; + } + } + return coeff; + } +}; + +template +CorreMatrix operator* (const NT k, CorreMatrix p){ + return p * k; +} + +template +std::ostream& operator<<(std::ostream& os, const CorreMatrix& p){ + os << p.mat; + return os; +} + +#endif //VOLESTI_CONVEX_BODIES_CORRELATION_MATRICES_CORRE_MATRIX_HPP diff --git a/include/convex_bodies/correlation_matrices/correlation_spectrahedron.hpp b/include/convex_bodies/correlation_matrices/correlation_spectrahedron.hpp new file mode 100755 index 000000000..ff8485477 --- /dev/null +++ b/include/convex_bodies/correlation_matrices/correlation_spectrahedron.hpp @@ -0,0 +1,267 @@ +// VolEsti (volume computation and sampling library) + +// Copyright (c) 2012-2020 Vissarion Fisikopoulos +// Copyright (c) 2020 Apostolos Chalkis + +// Contributed by Huu Phuoc Le as part of Google Summer of Code 2022 program + +// Licensed under GNU LGPL.3, see LICENCE file + +#ifndef VOLESTI_CONVEX_BODIES_CORRELATION_MATRICES_VOLESTI_CORRELATION_SPECTRAHEDRON_HPP +#define VOLESTI_CONVEX_BODIES_CORRELATION_MATRICES_VOLESTI_CORRELATION_SPECTRAHEDRON_HPP + +template +struct Precompute{ + + /// These flags indicate whether the corresponding matrices are computed + bool computed_A = false; + bool computed_B = false; + + /// The matrices the method positiveIntersection receives from its previous call + /// if the flag first_positive_intersection is true. + /// Matrix A is also used in coordinateIntersection + MT A, B; + + /// In method positive_intersect, the distance we are computing corresponds + /// to the minimum positive eigenvalue of a quadratic eigenvalue problem. + /// This will hold the eigenvector for that eigenvalue + VT eigenvector; + + /// Sets all flags to false + void resetFlags(){ + computed_A = computed_B = false; + } + + void set_mat_size(int const& n){ + A = -MT::Identity(n,n); + B.setZero(n, n); + eigenvector.setZero(n); + } +}; + +/// This class handles the spectrahedra of correlation matrices +/// The PointType here is stored as vector. +/// For the matrix PointType class, refer to CorrelationSpectrahedron_MT + +/// @tparam Point +template +class CorrelationSpectrahedron : public Spectrahedron{ + public: + + /// The numeric/matrix/vector types we use + typedef Point PointType; + typedef typename Point::FT NT; + typedef Eigen::Matrix MT; + typedef Eigen::Matrix VT; + typedef Precompute PrecomputationOfValues; + + /// The size of the matrix + unsigned int n; + + PrecomputationOfValues _precomputedValues; + + /// Constructor of correlation matrix spectrahedra + /// \param[in] : matrix size + CorrelationSpectrahedron(unsigned int n){ + int i,j; + this->n = n; + this->d = n*(n-1)/2; + this->_inner_ball.first = PointType(this->d); + this->_inner_ball.second = 1/std::sqrt(this->d); + _precomputedValues.set_mat_size(n); + } + + /// \returns The size of the matrix + unsigned int matrixSize() const { + return n; + } + + std::pair getInnerBall() const { + return this->_inner_ball; + } + + /// Build a correlation matrix from a vector of entries + /// \param[in] vector of coefficients + /// \param[in] the matrix to be assigned + void buildMatrix(VT const &pvector, unsigned int const n, MT &mat) const { + NT coeff; + int i, j, ind = 0; + for(i = 0; i < n ; ++i){ + mat(i,i) = -1; + } + for(i = 0; i < n ; ++i){ + for(j = 0; j < i; ++j){ + coeff = -pvector[ind]; + mat(i,j) = mat(j,i) = coeff; + ++ind; + } + } + } + + /// Computes the reflected direction at a point on the boundary of the spectrahedron. + /// \param[in] r A point on the boundary of the spectrahedron + /// \param[in] v The direction of the trajectory as it hits the boundary + /// \param[out] reflectedDirection The reflected direction + template + void compute_reflection(PointType &v, PointType const &r, update_parameters&) const { + VT grad(this->d); + VT e = _precomputedValues.eigenvector; + int i, j, ind = 0; + NT sum_sq = NT(0); + + for(i = 0; i < n ; ++i){ + for(j = 0; j < i; ++j){ + grad(ind) = e[i]*e[j]; + sum_sq += grad(ind)*grad(ind); + ++ind; + } + } + NT dot = v.dot(grad); + dot = 2 * dot / sum_sq; + v -= dot * PointType(grad); + } + + /// Construct the generalized eigenvalue problem \[Bt - A \] for positive_intersect. + /// \param[in] p Input vector + /// \param[in] v Input vector + /// \param[in, out] _precomputedValues Holds matrices B = I - A(v), A = A(p) + void createMatricesForPositiveLinearIntersection(VT const &p, VT const &v){ + if (true) { + VT pvector = p, vvector = v; + NT coeff; + int i, j, ind =0; + for(i = 0; i < n ; ++i){ + for(j = 0; j < i; ++j){ + coeff = -pvector[ind]; + _precomputedValues.A(i,j) = _precomputedValues.A(j,i) = coeff; + coeff = -vvector[ind]; + _precomputedValues.B(i,j) = _precomputedValues.B(j,i) = coeff; + ++ind; + } + } + _precomputedValues.computed_B = true; + } + } + + NT positiveLinearIntersection(VT const &p, VT const &v){ + createMatricesForPositiveLinearIntersection(p, v); + return this->EigenvaluesProblem.minPosLinearEigenvalue_EigenSymSolver(-_precomputedValues.A, _precomputedValues.B, _precomputedValues.eigenvector); + } + + // compute intersection point of a ray starting from r and pointing to v + // with polytope discribed by A and b + std::pair line_positive_intersect(PointType const &r, PointType const &v){ + NT pos_inter = positiveLinearIntersection(r.getCoefficients(), v.getCoefficients()); + return std::pair (pos_inter, -1); + } + + std::pair line_positive_intersect(PointType const &r, + PointType const &v, + VT&, + VT& , + NT const&){ + return line_positive_intersect(r, v); + } + + // compute intersection point of a ray starting from r and pointing to v + // with polytope discribed by A and b + std::pair line_positive_intersect(PointType const &r, + PointType const &v, + VT&, + VT&){ + return line_positive_intersect(r, v); + } + + template + std::pair line_positive_intersect(PointType const &r, + PointType const &v, + VT&, + VT& , + NT const&, + update_parameters&){ + return line_positive_intersect(r, v); + } + + template + std::pair line_positive_intersect(PointType const &r, + PointType const &v, + VT&, + VT&, + NT const&, + MT const&, + update_parameters&){ + return line_positive_intersect(r, v); + } + + template + std::pair line_first_positive_intersect(PointType const &r, + PointType const &v, + VT&, + VT&, + update_parameters&){ + return line_positive_intersect(r, v); + } + + // compute intersection point of ray starting from r and pointing to v + std::pair line_intersect(PointType const &r, PointType const &v){ + createMatricesForPositiveLinearIntersection(r.getCoefficients(), v.getCoefficients()); + return this->EigenvaluesProblem.symGeneralizedProblem(_precomputedValues.A, _precomputedValues.B); + } + + + std::pair line_intersect(PointType const &r, + PointType const &v, + VT&, + VT&){ + return line_intersect(r, v); + } + + std::pair line_intersect(PointType const &r, + PointType const &v, + VT&, + VT&, + NT&){ + return line_intersect(r, v); + } + + /// Compute the gradient of the determinant of the LMI at p + /// \param[in] p Input parameter + /// \param[in] Input vector: the eigenvector A(p)*e = 0 + /// \param[out] ret The unit normal vector at p + void unit_normal(VT p, VT const &e, VT &ret) const { + int i, j, ind = 0; + NT sum_sqqrt_sq = NT(0); + for(i = 0; i < n ; ++i){ + for(j = 0; j < i; ++j){ + ret(ind) = e[i]*e[j]; + sum_sqqrt_sq += ret(ind)*ret(ind); + ++ind; + } + } + ret /= std::sqrt(sum_sqqrt_sq); //normalize + } + + /// Test if a point p is in the spectrahedron + /// \param p is the current point + /// \return true if position is outside the spectrahedron + int is_in(PointType const &p, NT tol=NT(0)) const { + if(isExterior(p.getCoefficients())) return 0; + return -1; + } + + bool isExterior(VT const &pos) const { + MT mat = MT(n, n); + buildMatrix(pos, n, mat); + return isExterior(mat); + } + + bool isExterior(MT const &mat) const { + return !this->EigenvaluesProblem.isPositiveSemidefinite(-mat); + } + + MT get_mat() const { + return MT::Identity(this->d, this->d); + } +}; + +#endif //VOLESTI_CONVEX_BODIES_CORRELATION_MATRICES_VOLESTI_CORRELATION_SPECTRAHEDRON_HPP \ No newline at end of file diff --git a/include/convex_bodies/correlation_matrices/correlation_spectrahedron_MT.hpp b/include/convex_bodies/correlation_matrices/correlation_spectrahedron_MT.hpp new file mode 100755 index 000000000..239d9a3ad --- /dev/null +++ b/include/convex_bodies/correlation_matrices/correlation_spectrahedron_MT.hpp @@ -0,0 +1,180 @@ +// VolEsti (volume computation and sampling library) + +// Copyright (c) 2012-2020 Vissarion Fisikopoulos +// Copyright (c) 2020 Apostolos Chalkis + +// Contributed by Huu Phuoc Le as part of Google Summer of Code 2022 program + +// Licensed under GNU LGPL.3, see LICENCE file + +#ifndef VOLESTI_CONVEX_BODIES_CORRELATION_MATRICES_VOLESTI_CORRELATION_SPECTRAHEDRON_MT_HPP +#define VOLESTI_CONVEX_BODIES_CORRELATION_MATRICES_VOLESTI_CORRELATION_SPECTRAHEDRON_MT_HPP + +#include "convex_bodies/correlation_matrices/corre_matrix.hpp" +// +/// This class handles the spectrahedra of correlation matrices +/// @tparam Point +template +class CorrelationSpectrahedron_MT : public Spectrahedron{ + public: + + /// The numeric/matrix/vector types we use + typedef CorreMatrix PointType; + typedef typename PointType::FT NT; + typedef Eigen::Matrix MT; + typedef Eigen::Matrix VT; + + /// The size of the matrix + unsigned int n; + + VT eigenvector; + + /// Constructor of correlation matrix spectrahedra + /// \param[in] : matrix size + CorrelationSpectrahedron_MT(unsigned int n){ + int i,j; + this->n = n; + this->d = n*(n-1)/2; + this->_inner_ball.first = PointType(this->d); + this->_inner_ball.second = 1/std::sqrt(this->d); + this->eigenvector.setZero(n); + } + + /// \returns The size of the matrix + unsigned int matrixSize() const { + return n; + } + + std::pair getInnerBall() const { + return this->_inner_ball; + } + + /// Computes the reflected direction at a point on the boundary of the spectrahedron. + /// \param[in] r A point on the boundary of the spectrahedron + /// \param[in] v The direction of the trajectory as it hits the boundary + /// \param[out] reflectedDirection The reflected direction + template + void compute_reflection(PointType &v, PointType const &r, update_parameters&) const { + MT grad = MT::Zero(this->n, this->n); + int i, j; + NT sum_sq = NT(0), dot = NT(0); + + for(i = 0; i < n ; ++i){ + for(j = 0; j < i; ++j){ + grad(i,j) = eigenvector[i]*eigenvector[j]; + sum_sq += grad(i,j)*grad(i,j); + dot += grad(i,j) * v.mat(i,j); + } + } + dot = 2 * dot / sum_sq; + grad = dot*grad; + v -= PointType(grad); + } + + /// Computes the minimal positive t s.t. r+t*v intersects the boundary of the spectrahedron + /// \param[in] r + /// \param[in] v + /// \param[out] a NT value t + NT positiveLinearIntersection(PointType const &r, PointType const &v){ + + // minPosLinearEigenvalue_EigenSymSolver(A,B) computes the minimal positive eigenvalue of A-t*B + + return this->EigenvaluesProblem.minPosLinearEigenvalue_EigenSymSolver(r.mat, (-v).mat, eigenvector); + } + + // compute intersection point of a ray starting from r and pointing to v + // with polytope discribed by A and b + std::pair line_positive_intersect(PointType const &r, + PointType const &v) { + NT pos_inter = positiveLinearIntersection(r, v); + return std::pair (pos_inter, -1); + } + + std::pair line_positive_intersect(PointType const &r, + PointType const &v, + VT&, + VT& , + NT const&){ + return line_positive_intersect(r, v); + } + + // compute intersection point of a ray starting from r and pointing to v + // with polytope discribed by A and b + std::pair line_positive_intersect(PointType const &r, + PointType const &v, + VT&, + VT&){ + return line_positive_intersect(r, v); + } + + template + std::pair line_positive_intersect(PointType const &r, + PointType const &v, + VT&, + VT& , + NT const&, + update_parameters&){ + return line_positive_intersect(r, v); + } + + template + std::pair line_positive_intersect(PointType const &r, + PointType const &v, + VT&, + VT&, + NT const&, + MT const&, + update_parameters&){ + return line_positive_intersect(r, v); + } + + template + std::pair line_first_positive_intersect(PointType const &r, + PointType const &v, + VT&, + VT&, + update_parameters&){ + return line_positive_intersect(r, v); + } + + // compute intersection point of ray starting from r and pointing to v + std::pair line_intersect(PointType const &r, PointType const &v) const { + return this->EigenvaluesProblem.symGeneralizedProblem(-r.mat, -v.mat); + } + + std::pair line_intersect(PointType const &r, + PointType const &v, + VT&, + VT&) const { + return line_intersect(r, v); + } + + std::pair line_intersect(PointType const &r, + PointType const &v, + VT&, + VT&, + NT&) const { + return line_intersect(r, v); + } + + + /// Test if a point p is in the spectrahedron + /// \param p is the current point + /// \return true if position is outside the spectrahedron + int is_in(PointType const &p, NT tol=NT(0)) const { + if(this->EigenvaluesProblem.isPositiveSemidefinite(p.mat)){ + return -1; + } + return 0; + } + + bool isExterior(MT const &mat) const { + return !this->EigenvaluesProblem.isPositiveSemidefinite(mat); + } + + MT get_mat() const { + return MT::Identity(this->d, this->d); + } +}; + +#endif //VOLESTI_CONVEX_BODIES_CORRELATION_MATRICES_VOLESTI_CORRELATION_SPECTRAHEDRON_MT_HPP diff --git a/include/convex_bodies/spectrahedra/spectrahedron.h b/include/convex_bodies/spectrahedra/spectrahedron.h index f7fb4bd9f..22467ee0c 100644 --- a/include/convex_bodies/spectrahedra/spectrahedron.h +++ b/include/convex_bodies/spectrahedra/spectrahedron.h @@ -3,7 +3,8 @@ // Copyright (c) 2012-2020 Vissarion Fisikopoulos // Copyright (c) 2020 Apostolos Chalkis -//Contributed and/or modified by Repouskos Panagiotis, as part of Google Summer of Code 2019 program. +// Contributed and/or modified by Repouskos Panagiotis, as part of Google Summer of Code 2019 program. +// Modified by Huu Phuoc Le as part of Google Summer of Code 2022 program // Licensed under GNU LGPL.3, see LICENCE file @@ -42,7 +43,7 @@ struct PrecomputationOfValues { computed_XY = computed_C = computed_A = false; } - void set_mat_size(int const& m) + void set_mat_size(int const& m) { A.setZero(m, m); B.setZero(m, m); @@ -78,7 +79,7 @@ class Spectrahedron { typedef PrecomputationOfValues _PrecomputationOfValues; _PrecomputationOfValues precomputedValues; - + EigenvaluesProblems EigenvaluesProblem; /// The dimension of the spectrahedron @@ -106,7 +107,6 @@ class Spectrahedron { } std::pair ComputeInnerBall() { - NT radius = maxDouble; for (unsigned int i = 0; i < dimension(); ++i) { @@ -123,6 +123,11 @@ class Spectrahedron { return std::pair(_inner_ball.first, radius); } + std::pair InnerBall() const + { + return _inner_ball; + } + /// Construct the quadratic eigenvalue problem \[At^2 + Bt + C \] for positive_intersect. /// A = lmi(c) - A0, B = lmi(b) - A0 and C = lmi(c). /// \param[in] a Input vector @@ -162,9 +167,9 @@ class Spectrahedron { void createMatricesForPositiveIntersection(const VT& p, const VT& v) { - + // check if matrices B, C are ready if not compute them - if (!precomputedValues.computed_C) + if (!precomputedValues.computed_C) { lmi.evaluate(p, precomputedValues.C); } @@ -198,7 +203,7 @@ class Spectrahedron { } - NT positiveLinearIntersection(VT const & p, VT const & v) + NT positiveLinearIntersection(VT const & p, VT const & v) { createMatricesForPositiveLinearIntersection(p, v); NT distance = EigenvaluesProblem.minPosLinearEigenvalue(precomputedValues.C, precomputedValues.B, @@ -250,6 +255,14 @@ class Spectrahedron { return std::pair (pos_inter, -1); } + std::pair line_positive_intersect(PointType const& r, + PointType const& v, + VT&, + VT& , + NT const&) { + return line_positive_intersect(r, v); + } + template std::pair line_positive_intersect(PointType const& r, PointType const& v, @@ -298,7 +311,7 @@ class Spectrahedron { std::pair line_intersect(PointType const& r, PointType const& v) { NT pos_inter = positiveLinearIntersection(r.getCoefficients(), v.getCoefficients()); - NT neg_inter = positiveLinearIntersection(r.getCoefficients(), NT(-1)*v.getCoefficients()); + NT neg_inter = -positiveLinearIntersection(r.getCoefficients(), NT(-1)*v.getCoefficients()); return std::make_pair(pos_inter, neg_inter); } @@ -379,7 +392,7 @@ class Spectrahedron { /// \param[in] v The direction of the trajectory as it hits the boundary /// \param[out] reflectedDirection The reflected direction template - void compute_reflection(PointType &v, PointType const& r, update_parameters& ) const + void compute_reflection(PointType &v, PointType const& r, update_parameters& ) const { VT grad(d); lmi.normalizedDeterminantGradient(r.getCoefficients(), precomputedValues.eigenvector, grad); @@ -455,25 +468,25 @@ class Spectrahedron { return maxDistance; } - int is_in(PointType const& p, NT tol=NT(0)) + int is_in(PointType const& p, NT tol=NT(0)) const { if (isExterior(p.getCoefficients())) { return 0; } return -1; } - + /// Find out is lmi(current position) = mat is in the exterior of the spectrahedron /// \param mat a matrix where mat = lmi(current position) /// \return true if position is outside the spectrahedron - bool isExterior(MT const & mat) { + bool isExterior(MT const & mat) const { return !lmi.isNegativeSemidefinite(mat); } /// Find out is pos is in the exterior of the spectrahedron /// \param pos a vector /// \return true if pos is outside the spectrahedron - bool isExterior(VT const & pos) { + bool isExterior(VT const & pos) const { return !lmi.isNegativeSemidefinite(pos); } }; diff --git a/include/matrix_operations/EigenvaluesProblems.h b/include/matrix_operations/EigenvaluesProblems.h index 31d62159e..8a22408b0 100644 --- a/include/matrix_operations/EigenvaluesProblems.h +++ b/include/matrix_operations/EigenvaluesProblems.h @@ -4,6 +4,7 @@ // Copyright (c) 2020 Apostolos Chalkis //Contributed and/or modified by Repouskos Panagiotis, as part of Google Summer of Code 2019 program. +// Contributed and modified by Huu Phuoc Le as part of Google Summer of Code 2022 program // Licensed under GNU LGPL.3, see LICENCE file @@ -122,7 +123,7 @@ class EigenvaluesProblems, E /// \param[in] A Input matrix /// \param[in] B Input matrix /// \return The pair (minimum positive, maximum negative) of eigenvalues - NTpair symGeneralizedProblem(MT const & A, MT const & B) { + NTpair symGeneralizedProblem(MT const & A, MT const & B) const { int matrixDim = A.rows(); @@ -159,8 +160,7 @@ class EigenvaluesProblems, E return {lambdaMinPositive, lambdaMaxNegative}; } - NT minPosLinearEigenvalue(MT const & A, MT const & B, VT &eigvec) - { + NT minPosLinearEigenvalue(MT const & A, MT const & B, VT &eigvec) { int matrixDim = A.rows(); double lambdaMinPositive; @@ -317,8 +317,7 @@ class EigenvaluesProblems, E /// \param[in] A Input matrix /// \param[in] B Input matrix /// \return The pair (minimum positive, maximum negative) of eigenvalues - NT minPosLinearEigenvalue(MT const & A, MT const & B, VT &eigvec) const - { + NT minPosLinearEigenvalue(MT const & A, MT const & B, VT &eigvec) const { int matrixDim = A.rows(); double lambdaMinPositive; @@ -395,8 +394,7 @@ class EigenvaluesProblems, E /// \param[out] eigenvector The eigenvector corresponding to the minimum positive eigenvalue /// \param[in, out] updateOnly True if X,Y were previously computed and only B,C changed /// \return Minimum positive eigenvalue - NT - minPosQuadraticEigenvalue(MT const & A, MT const &B, MT const &C, MT &X, MT &Y, VT &eigenvector, bool &updateOnly) { + NT minPosQuadraticEigenvalue(MT const & A, MT const &B, MT const &C, MT &X, MT &Y, VT &eigenvector, bool &updateOnly) { // perform linearization and create generalized eigenvalue problem X+lY linearization(A, B, C, X, Y, updateOnly); @@ -424,6 +422,29 @@ class EigenvaluesProblems, E return lambdaMinPositive; } + + // Using LDLT decomposition to check membership + // Faster than computing the largest eigenvalue with Spectra + // more numerically stable for singular matrices + bool isPositiveSemidefinite(MT const &A) const { + Eigen::LDLT A_ldlt(A); + if (A_ldlt.info() != Eigen::NumericalIssue && A_ldlt.isPositive()) + return true; + return false; + } + + /// Minimum positive eigenvalue of the generalized eigenvalue problem A - lB + /// Use Eigen::GeneralizedSelfAdjointEigenSolver ges(B,A) (faster) + /// \param[in] A: symmetric positive definite matrix + /// \param[in] B: symmetric matrix + /// \return The minimum positive eigenvalue and the corresponding eigenvector + NT minPosLinearEigenvalue_EigenSymSolver(MT const & A, MT const & B, VT &eigvec) const { + NT lambdaMinPositive = NT(0); + Eigen::GeneralizedSelfAdjointEigenSolver ges(B,A); + lambdaMinPositive = 1/ges.eigenvalues().reverse()[0]; + eigvec = ges.eigenvectors().reverse().col(0).reverse(); + return lambdaMinPositive; + } }; #endif //VOLESTI_EIGENVALUESPROBLEMS_H diff --git a/include/random_walks/compute_diameter.hpp b/include/random_walks/compute_diameter.hpp index f1d8340b6..e3ec0f441 100644 --- a/include/random_walks/compute_diameter.hpp +++ b/include/random_walks/compute_diameter.hpp @@ -51,6 +51,28 @@ struct compute_diameter> } }; +template +struct compute_diameter> +{ + template + static NT compute(CorrelationSpectrahedron &P) + { + std::pair inner_ball = P.getInnerBall(); + return NT(P.dimension()) * inner_ball.second; + } +}; + +template +struct compute_diameter> +{ + template + static NT compute(CorrelationSpectrahedron_MT &P) + { + std::pair inner_ball = P.getInnerBall(); + return NT(P.dimension()) * inner_ball.second; + } +}; + #ifndef DISABLE_LPSOLVE template struct compute_diameter> diff --git a/include/random_walks/random_walks.hpp b/include/random_walks/random_walks.hpp index cc5dc089a..4affee74d 100644 --- a/include/random_walks/random_walks.hpp +++ b/include/random_walks/random_walks.hpp @@ -8,6 +8,8 @@ #ifndef RANDOM_WALKS_RANDOM_WALKS_HPP #define RANDOM_WALKS_RANDOM_WALKS_HPP +#include + #include "random_walks/boundary_cdhr_walk.hpp" #include "random_walks/boundary_rdhr_walk.hpp" #include "random_walks/gaussian_ball_walk.hpp" diff --git a/include/random_walks/uniform_billiard_walk.hpp b/include/random_walks/uniform_billiard_walk.hpp index 90c6378df..dcbc96b10 100644 --- a/include/random_walks/uniform_billiard_walk.hpp +++ b/include/random_walks/uniform_billiard_walk.hpp @@ -4,6 +4,7 @@ // Copyright (c) 2018-2020 Apostolos Chalkis // Contributed and/or modified by Apostolos Chalkis, as part of Google Summer of Code 2019 program. +// Contributed and modified by Huu Phuoc Le as part of Google Summer of Code 2022 program // Licensed under GNU LGPL.3, see LICENCE file @@ -16,6 +17,8 @@ #include "convex_bodies/ballintersectconvex.h" #include "convex_bodies/hpolytope.h" #include "convex_bodies/spectrahedra/spectrahedron.h" +#include "convex_bodies/correlation_matrices/correlation_spectrahedron.hpp" +#include "convex_bodies/correlation_matrices/correlation_spectrahedron_MT.hpp" #ifndef DISABLE_LPSOLVE #include "convex_bodies/vpolytope.h" #include "convex_bodies/vpolyintersectvpoly.h" @@ -29,7 +32,6 @@ #include "volume/sampling_policies.hpp" #include "random_walks/compute_diameter.hpp" - // Billiard walk for uniform distribution struct BilliardWalk @@ -99,21 +101,26 @@ struct Walk { T = rng.sample_urdist() * _Len; _v = GetDirection::apply(n, rng); + Point p0 = _p; int it = 0; while (it < 50*n) { auto pbpair = P.line_positive_intersect(_p, _v, _lambdas, _Av, _lambda_prev); + if (T <= pbpair.first) { _p += (T * _v); _lambda_prev = T; break; } + _lambda_prev = dl * pbpair.first; _p += (_lambda_prev * _v); T -= _lambda_prev; + P.compute_reflection(_v, _p, pbpair.second); + it++; } if (it == 50*n){ @@ -148,7 +155,6 @@ private : NT T = rng.sample_urdist() * _Len; Point p0 = _p; int it = 0; - std::pair pbpair = P.line_positive_intersect(_p, _v, _lambdas, _Av); if (T <= pbpair.first) { @@ -160,7 +166,6 @@ private : _p += (_lambda_prev * _v); T -= _lambda_prev; P.compute_reflection(_v, _p, pbpair.second); - while (it <= 50*n) { std::pair pbpair @@ -192,11 +197,4 @@ private : }; - - - - - - - #endif // RANDOM_WALKS_UNIFORM_BILLIARD_WALK_HPP diff --git a/include/sampling/sample_correlation_matrices.hpp b/include/sampling/sample_correlation_matrices.hpp new file mode 100644 index 000000000..9a1de2319 --- /dev/null +++ b/include/sampling/sample_correlation_matrices.hpp @@ -0,0 +1,153 @@ +// VolEsti (volume computation and sampling library) + +// Copyright (c) 2012-2020 Vissarion Fisikopoulos +// Copyright (c) 2020 Apostolos Chalkis + +// Contributed by Huu Phuoc Le as part of Google Summer of Code 2022 program + +// Licensed under GNU LGPL.3, see LICENCE file + +/// Functions to sample correlation matrices w.r.t. a truncated density + +#ifndef VOLESTI_SAMPLING_SAMPLE_CORRELATION_MATRICES_HPP +#define VOLESTI_SAMPLING_SAMPLE_CORRELATION_MATRICES_HPP + +#include + +// New implementations for sampling correlation matrices with CorrelationSpectrahedron and CorrelationSpectrahedron_MT + +template +< + typename WalkTypePolicy, + typename PointType, + typename RNGType, + typename PointList +> +void uniform_correlation_sampling(const unsigned int &n, + PointList &randPoints, + const unsigned int &walkL, + const unsigned int &num_points, + unsigned int const& nburns){ + CorrelationSpectrahedron P(n); + const unsigned int d = P.dimension(); + PointType startingPoint(d); + RNGType rng(d); + + uniform_sampling(randPoints, P, rng, walkL, num_points, startingPoint, nburns); +} + +template +< + typename WalkTypePolicy, + typename PointType, + typename RNGType, + typename PointList +> +void uniform_correlation_sampling_MT( const unsigned int &n, + PointList &randPoints, + const unsigned int &walkL, + const unsigned int &num_points, + unsigned int const& nburns){ + CorrelationSpectrahedron_MT P(n); + const unsigned int d = P.dimension(); + PointType startingPoint(n); + RNGType rng(d); + + uniform_sampling(randPoints, P, rng, walkL, num_points, startingPoint, nburns); +} + +template +< + typename WalkTypePolicy, + typename PointType, + typename RNGType, + typename PointList, + typename NT +> +void gaussian_correlation_sampling( const unsigned int &n, + PointList &randPoints, + const unsigned int &walkL, + const unsigned int &num_points, + const NT &a, + unsigned int const& nburns = 0){ + CorrelationSpectrahedron P(n); + const unsigned int d = P.dimension(); + PointType startingPoint(d); + RNGType rng(d); + + gaussian_sampling(randPoints, P, rng, walkL, num_points, a, startingPoint, nburns); +} + +template +< + typename WalkTypePolicy, + typename PointType, + typename RNGType, + typename PointList, + typename NT +> +void gaussian_correlation_sampling_MT( const unsigned int &n, + PointList &randPoints, + const unsigned int &walkL, + const unsigned int &num_points, + const NT &a, + unsigned int const& nburns = 0){ + CorrelationSpectrahedron_MT P(n); + const unsigned int d = P.dimension(); + PointType startingPoint(n); + RNGType rng(d); + + gaussian_sampling(randPoints, P, rng, walkL, num_points, a, startingPoint, nburns); +} + +template +< + typename WalkTypePolicy, + typename PointType, + typename RNGType, + typename PointList, + typename NT, + typename VT +> +void exponential_correlation_sampling( const unsigned int &n, + PointList &randPoints, + const unsigned int &walkL, + const unsigned int &num_points, + const VT &c, + const NT &T, + unsigned int const& nburns = 0){ + CorrelationSpectrahedron P(n); + const unsigned int d = P.dimension(); + PointType startingPoint(d); + RNGType rng(d); + PointType _c(c); + + exponential_sampling(randPoints, P, rng, walkL, num_points, _c, T, startingPoint, nburns); +} + +template +< + typename WalkTypePolicy, + typename PointType, + typename RNGType, + typename PointList, + typename NT, + typename VT +> +void exponential_correlation_sampling_MT( const unsigned int &n, + PointList &randPoints, + const unsigned int &walkL, + const unsigned int &num_points, + const VT &c, + const NT &T, + unsigned int const& nburns = 0){ + CorrelationSpectrahedron_MT P(n); + const unsigned int d = P.dimension(); + PointType startingPoint(n); + RNGType rng(d); + PointType _c(c); + + exponential_sampling(randPoints, P, rng, walkL, num_points, _c, T, startingPoint, nburns); +} + +#endif //VOLESTI_SAMPLING_SAMPLE_CORRELATION_MATRICES_HPP diff --git a/include/sampling/sphere.hpp b/include/sampling/sphere.hpp index 8bd3ccc7f..0a8905f92 100644 --- a/include/sampling/sphere.hpp +++ b/include/sampling/sphere.hpp @@ -4,6 +4,7 @@ // Copyright (c) 2018-2020 Apostolos Chalkis //Contributed and/or modified by Repouskos Panagiotis, as part of Google Summer of Code 2019 program. +// Contributed and modified by Huu Phuoc Le as part of Google Summer of Code 2022 program // Licensed under GNU LGPL.3, see LICENCE file @@ -11,6 +12,7 @@ #ifndef SAMPLERS_SPHERE_HPP #define SAMPLERS_SPHERE_HPP +#include "convex_bodies/correlation_matrices/corre_matrix.hpp" template struct GetDirection @@ -26,17 +28,72 @@ struct GetDirection Point p(dim); NT* data = p.pointerToData(); - for (unsigned int i=0; i +struct GetDirection> +{ + template + inline static CorreMatrix apply(unsigned int const& dim, + RandomNumberGenerator &rng, + bool normalize=true) + { + typedef Eigen::Matrix MT; + typedef Eigen::Matrix VT; - return p; + unsigned int n = std::ceil(std::sqrt(2*dim)); + MT mat = MT::Zero(n,n); + NT normal = NT(0), coeff; + + int i, j; + + if(normalize) + { + for(i = 0; i < n ; ++i) + { + for(j = 0; j < i; ++j) + { + coeff = rng.sample_ndist(); + mat(i,j) = coeff; + normal += coeff * coeff; + } + } + normal = NT(1)/std::sqrt(normal); + mat *= normal; + }else + { + for(i = 0; i < n ; ++i) + { + for(j = 0; j < i; ++j) + { + coeff = rng.sample_ndist(); + mat(i,j) = coeff; + } + } + } + return CorreMatrix(mat); } }; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index eeaecabcd..ddd40e362 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -344,6 +344,17 @@ else () add_test(NAME order_polytope_line_intersect COMMAND order_polytope -tc=line_intersect) add_test(NAME order_polytope_reflection COMMAND order_polytope -tc=reflection) add_test(NAME order_polytope_vec_mult COMMAND order_polytope -tc=vec_mult) + + add_executable (matrix_sampling_test sampling_correlation_matrices_test.cpp $) + add_test(NAME test_corre_spectra_classes COMMAND matrix_sampling_test -tc=corre_spectra) + add_test(NAME test_new_ball_uniform COMMAND matrix_sampling_test -tc=new_ball_uniform) + add_test(NAME test_new_billiard_uniform COMMAND matrix_sampling_test -tc=new_billiard_uniform) + add_test(NAME test_new_accelerated_billiard_uniform COMMAND matrix_sampling_test -tc=new_accelerated_billiard_uniform) + add_test(NAME test_new_ball_uniform_MT COMMAND matrix_sampling_test -tc=new_ball_uniform_MT) + add_test(NAME test_new_rdhr_uniform_MT COMMAND matrix_sampling_test -tc=new_rdhr_uniform_MT) + add_test(NAME test_new_billiard_uniform_MT COMMAND matrix_sampling_test -tc=new_billiard_uniform_MT) + add_test(NAME test_new_accelerated_billiard_uniform_MT COMMAND matrix_sampling_test -tc=new_accelerated_billiard_uniform_MT) + set(ADDITIONAL_FLAGS "-march=native -DSIMD_LEN=0 -DTIME_KEEPING") #set_target_properties(benchmarks_crhmc @@ -354,6 +365,7 @@ else () PROPERTIES COMPILE_FLAGS ${ADDITIONAL_FLAGS}) set_target_properties(crhmc_sampling_test PROPERTIES COMPILE_FLAGS ${ADDITIONAL_FLAGS}) + TARGET_LINK_LIBRARIES(new_volume_example ${LP_SOLVE} ${MKL_LINK} coverage_config) TARGET_LINK_LIBRARIES(new_volume_example ${LP_SOLVE} coverage_config) TARGET_LINK_LIBRARIES(volume_sob_hpolytope ${LP_SOLVE} coverage_config) @@ -382,6 +394,6 @@ else () TARGET_LINK_LIBRARIES(logconcave_sampling_test ${LP_SOLVE} ${IFOPT} ${IFOPT_IPOPT} ${PTHREAD} ${GMP} ${MPSOLVE} ${FFTW3} ${MKL_LINK} coverage_config) TARGET_LINK_LIBRARIES(crhmc_sampling_test ${LP_SOLVE} ${IFOPT} ${IFOPT_IPOPT} ${PTHREAD} ${GMP} ${MPSOLVE} ${FFTW3} ${MKL_LINK} ${QD_LIB} coverage_config) TARGET_LINK_LIBRARIES(order_polytope ${LP_SOLVE} coverage_config) - + TARGET_LINK_LIBRARIES(matrix_sampling_test ${LP_SOLVE} ${MKL_LINK} coverage_config) endif() diff --git a/test/sampling_correlation_matrices_test.cpp b/test/sampling_correlation_matrices_test.cpp new file mode 100644 index 000000000..f2f90c529 --- /dev/null +++ b/test/sampling_correlation_matrices_test.cpp @@ -0,0 +1,207 @@ +// VolEsti (volume computation and sampling library) + +// Copyright (c) 2012-2020 Vissarion Fisikopoulos +// Copyright (c) 2020 Apostolos Chalkis + +// Contributed by Huu Phuoc Le as part of Google Summer of Code 2022 program + +// Licensed under GNU LGPL.3, see LICENCE file + +#include "doctest.h" +#include +#include "misc.h" +#include "random.hpp" +#include "random/uniform_int.hpp" +#include "random/normal_distribution.hpp" +#include "random/uniform_real_distribution.hpp" + +#include "cartesian_geom/cartesian_kernel.h" +#include "random_walks/random_walks.hpp" +#include "sampling/sample_correlation_matrices.hpp" + +#include "diagnostics/univariate_psrf.hpp" + +template +MT rebuildMatrix(const VT &xvector, const unsigned int n){ + MT mat = MT::Identity(n,n); + NT coeff; + int i, j, ind = 0; + for(i = 0; i < n ; ++i){ + for(j = 0; j < i; ++j){ + coeff = xvector[ind]; + mat(i,j) = mat(j,i) = coeff; + ++ind; + } + } + return mat; +} + +template +void check_output(PointList &randPoints, int num_points, int n){ + int d = n*(n-1)/2, count = 0; + MT A; + Eigen::LDLT A_ldlt; + for(int i = 0; i < num_points ; ++i){ + A = rebuildMatrix(randPoints[i].getCoefficients(), n); + A_ldlt = Eigen::LDLT(A); + if (A_ldlt.info() == Eigen::NumericalIssue || !A_ldlt.isPositive()){ + ++count; + } + } + std::cout << "Fails " << count << " / " << num_points << " samples\n"; + CHECK(count == 0); + + MT samples(d, num_points); + unsigned int jj = 0; + + for (typename PointList::iterator rpit = randPoints.begin(); rpit!=randPoints.end(); rpit++, jj++){ + samples.col(jj) = (*rpit).getCoefficients(); + } + + VT score = univariate_psrf(samples); + std::cout << "psrf = " << score.maxCoeff() << std::endl; + + CHECK(score.maxCoeff() < 1.1); +} + +template +void test_corre_spectra_classes(unsigned int const n){ + typedef Cartesian Kernel; + typedef typename Kernel::Point Point; + typedef Eigen::Matrix MT; + typedef Eigen::Matrix VT; + typedef BoostRandomNumberGenerator RNGType; + typedef CorreMatrix PMT; + + const unsigned int d = n*(n-1)/2; + RNGType rng(d); + + CorrelationSpectrahedron P(n); + Point startingPoint(d); + + CHECK(P.matrixSize() == n); + CHECK(P.dimension() == d); + CHECK(P.is_in(startingPoint) == -1); + std::cout << "Diameter of P = " << P.InnerBall().second < P2(n); + + CHECK(P2.matrixSize() == n); + CHECK(P2.dimension() == d); + + PMT startingPoint2(d); + CHECK(P2.is_in(startingPoint2) == -1); + PMT A = GetDirection::apply(P2.dimension(), rng); +} + +template +< + typename NT, + typename WalkType +> +void test_new_uniform(const unsigned int n, const unsigned int num_points = 1000){ + typedef Cartesian Kernel; + typedef typename Kernel::Point Point; + typedef Eigen::Matrix MT; + typedef Eigen::Matrix VT; + typedef BoostRandomNumberGenerator RNGType; + + std::cout << "Test new sampling : "<< num_points << " uniform correlation matrices of size " << n << std::endl; + std::chrono::steady_clock::time_point start, end; + double time; + std::vector randPoints; + unsigned int walkL = 1; + + start = std::chrono::steady_clock::now(); + + uniform_correlation_sampling(n, randPoints, walkL, num_points, 0); + + end = std::chrono::steady_clock::now(); + time = std::chrono::duration_cast(end - start).count(); + std::cout << "Elapsed time : " << time << " (ms)" << std::endl; + + check_output(randPoints, num_points, n); +} + +template +< + typename NT, + typename WalkType +> +void test_new_uniform_MT(const unsigned int n, const unsigned int num_points = 1000){ + typedef CorreMatrix Point; + typedef Eigen::Matrix MT; + typedef Eigen::Matrix VT; + typedef BoostRandomNumberGenerator RNGType; + std::cout << "Test new sampling 2 : "<< num_points << " uniform correlation matrices of size " << n << std::endl; + std::chrono::steady_clock::time_point start, end; + double time; + std::vector randPoints; + unsigned int walkL = 1; + + start = std::chrono::steady_clock::now(); + + uniform_correlation_sampling_MT(n, randPoints, walkL, num_points, 0); + + end = std::chrono::steady_clock::now(); + time = std::chrono::duration_cast(end - start).count(); + std::cout << "Elapsed time : " << time << " (ms)" << std::endl; + + check_output(randPoints, num_points, n); +} + +int n = 3; +int num_points_BallWalk = 10000; +int num_points_RDHRWalk = 10000; +int num_points_BilliardWalk = 1000; + +/////////////////////////////////////////////////////////////////// +// Test new classes +// + +TEST_CASE("corre_spectra") { + test_corre_spectra_classes(n); +} + +/////////////////////////////////////////////////////////////////// +// New implementation : CorrelationSpectrahedron Vector PointType +// + +TEST_CASE("new_ball_uniform") { + std::cout << "Ball Walk :: "; + test_new_uniform(n,num_points_BallWalk); +} + +TEST_CASE("new_billiard_uniform") { + std::cout << "Billiard Walk :: "; + test_new_uniform(n, num_points_BilliardWalk); +} + +TEST_CASE("new_accelerated_billiard_uniform") { + std::cout << "Accelerated Billiard Walk :: "; + test_new_uniform(n, num_points_BilliardWalk); +} + +/////////////////////////////////////////////////////////////////// +// New implementation : CorrelationSpectrahedron Matrix PointType +// + +TEST_CASE("new_ball_uniform_MT") { + std::cout << "Ball Walk MT :: "; + test_new_uniform_MT(n,num_points_BallWalk); +} + +TEST_CASE("new_rdhr_uniform_MT") { + std::cout << "RDHR Walk MT :: "; + test_new_uniform_MT(n,num_points_RDHRWalk); +} + +TEST_CASE("new_billiard_uniform_MT") { + std::cout << "Billiard Walk MT :: "; + test_new_uniform_MT(n, num_points_BilliardWalk); +} + +TEST_CASE("new_accelerated_billiard_uniform_MT") { + std::cout << "Accelerated Billiard Walk MT :: "; + test_new_uniform_MT(n, num_points_BilliardWalk); +} From bf9c232983274e85171a60b383355ddf258c15fe Mon Sep 17 00:00:00 2001 From: Vissarion Fisikopoulos Date: Thu, 3 Nov 2022 11:02:43 +0200 Subject: [PATCH 12/20] Add documentation actions and fix doc issues (#248) --- .github/workflows/docs.yml | 27 +++++++++++++++++++ .../correlation_spectrahedron.hpp | 3 +-- .../correlation_spectrahedron_MT.hpp | 4 +-- 3 files changed, 30 insertions(+), 4 deletions(-) create mode 100644 .github/workflows/docs.yml diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 000000000..fca7ede90 --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,27 @@ +name: Docs +on: [push, pull_request] + +jobs: + notebooks: + name: "Build the docs" + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + + - name: Set up Python + uses: actions/setup-python@v2 + with: + python-version: 3.8 + + - name: Install dependencies + run: | + sudo apt-get install doxygen + python -m pip install -U pip + python -m pip install -r docs/requirements.txt + + - name: Build the docs + run: | + python -m pip install -U setuptools + python -m pip install -U pillow mock alabaster commonmark recommonmark sphinx sphinx-rtd-theme readthedocs-sphinx-ext + cd docs + python -m sphinx -T -E -b html -d _build/doctrees -D language=en . _build/html diff --git a/include/convex_bodies/correlation_matrices/correlation_spectrahedron.hpp b/include/convex_bodies/correlation_matrices/correlation_spectrahedron.hpp index ff8485477..275ad604a 100755 --- a/include/convex_bodies/correlation_matrices/correlation_spectrahedron.hpp +++ b/include/convex_bodies/correlation_matrices/correlation_spectrahedron.hpp @@ -43,7 +43,6 @@ struct Precompute{ /// The PointType here is stored as vector. /// For the matrix PointType class, refer to CorrelationSpectrahedron_MT -/// @tparam Point template class CorrelationSpectrahedron : public Spectrahedron{ public: @@ -61,7 +60,7 @@ class CorrelationSpectrahedron : public Spectrahedron{ PrecomputationOfValues _precomputedValues; /// Constructor of correlation matrix spectrahedra - /// \param[in] : matrix size + CorrelationSpectrahedron(unsigned int n){ int i,j; this->n = n; diff --git a/include/convex_bodies/correlation_matrices/correlation_spectrahedron_MT.hpp b/include/convex_bodies/correlation_matrices/correlation_spectrahedron_MT.hpp index 239d9a3ad..9c7abe583 100755 --- a/include/convex_bodies/correlation_matrices/correlation_spectrahedron_MT.hpp +++ b/include/convex_bodies/correlation_matrices/correlation_spectrahedron_MT.hpp @@ -13,7 +13,7 @@ #include "convex_bodies/correlation_matrices/corre_matrix.hpp" // /// This class handles the spectrahedra of correlation matrices -/// @tparam Point + template class CorrelationSpectrahedron_MT : public Spectrahedron{ public: @@ -30,7 +30,7 @@ class CorrelationSpectrahedron_MT : public Spectrahedron{ VT eigenvector; /// Constructor of correlation matrix spectrahedra - /// \param[in] : matrix size + CorrelationSpectrahedron_MT(unsigned int n){ int i,j; this->n = n; From ba0e697a414bda101c8010676cc929131da2f064 Mon Sep 17 00:00:00 2001 From: Gabriele Masina Date: Wed, 9 Nov 2022 21:11:48 +0100 Subject: [PATCH 13/20] Add rng parameter for MC integration + fix dimension bug (#251) * Add rng parameter for MC integration + fix dimension bug * Fix parameters order * Adjust coding style (spaces) * Change order of parameters `dim` and `rng` in mc integration * Pass `rng` parameter to mc integration function in tests * Indent using spaces --- include/integration/simple_MC_integration.hpp | 122 ++++-- test/simple_mc_integration.cpp | 393 ++++++++++-------- 2 files changed, 296 insertions(+), 219 deletions(-) diff --git a/include/integration/simple_MC_integration.hpp b/include/integration/simple_MC_integration.hpp index f6cb1739c..58739650d 100644 --- a/include/integration/simple_MC_integration.hpp +++ b/include/integration/simple_MC_integration.hpp @@ -34,7 +34,7 @@ typedef HPolytope Hpolytope; typedef boost::mt19937 RNGType; typedef BoostRandomNumberGenerator RandomNumberGenerator; typedef typename HPolytope::MT MT; -typedef typename HPolytope::VT VT; +typedef typename HPolytope::VT VT; enum volumetype {CB ,CG ,SOB}; // Volume type for polytope typedef typename std::vector Limit; // Standard way for user to use limits @@ -97,7 +97,7 @@ void initiate_unit_limits(Point& LL, Point& UL, int dim) { } // Simple MC Integration Over Polytopes -template +template < typename WalkType = BallWalk, typename Polytope = Hpolytope, @@ -106,13 +106,14 @@ template typename NT = NT, typename Functor > -NT simple_mc_polytope_integrate(Functor Fx, - Polytope &P, - int N = 10000, - volumetype voltype = SOB, - int walk_length = 1, - NT e = 0.1, - Point Origin = pt) +NT simple_mc_polytope_integrate(Functor Fx, + Polytope &P, + RNG &rng, + int N = 10000, + volumetype voltype = SOB, + int walk_length = 1, + NT e = 0.1, + Point Origin = pt) { int dim = P.dimension(); @@ -120,7 +121,7 @@ NT simple_mc_polytope_integrate(Functor Fx, // Check if ShiftPoint is shifted with accurate dimensions if (Origin.dimension() == 0 && dim > 0) { - Origin.set_dimension(dim); + Origin.set_dimension(dim); Origin.set_to_origin(); } else if (Origin.dimension() != dim && dim > 0) { std::cerr << "Polytope Dimension != Shiftpoint Dimension" << std::endl; @@ -132,16 +133,16 @@ NT simple_mc_polytope_integrate(Functor Fx, // Volume calculation for HPolytope NT volume; - + switch (voltype) { - case CB: - volume = volume_cooling_balls (P, e, walk_length).second; + case CB: + volume = volume_cooling_balls (P, rng, e, walk_length).second; break; - case CG: - volume = volume_cooling_gaussians (P, e, walk_length); + case CG: + volume = volume_cooling_gaussians (P, rng, e, walk_length); break; - case SOB: - volume = volume_sequence_of_balls (P, e, walk_length); + case SOB: + volume = volume_sequence_of_balls (P, rng, e, walk_length); break; default: std::cerr << "Error in volume type: CB / SOB / CG" << std::endl; @@ -151,7 +152,6 @@ NT simple_mc_polytope_integrate(Functor Fx, // std::cout << "Volume of the convex body = " << volume << std::endl; // For implementing Uniform Walks - RNG rng(1); std::pair inner_ball = P.ComputeInnerBall(); Point x0 = inner_ball.first; typename WalkType::template Walk walk(P, x0, rng); @@ -162,15 +162,37 @@ NT simple_mc_polytope_integrate(Functor Fx, for (int i = 0; i < N; i++) { walk.apply(P, x0, walk_length, rng); sum += Fx(x0 + Origin); - + // (x0 + Origin).print(); - } + } // Integration Value NT integration_value = volume * sum / N ; return integration_value; } +template +< + typename WalkType = BallWalk, + typename Polytope = Hpolytope, + typename VolumeWalkType = BallWalk, + typename RNG = RandomNumberGenerator, + typename NT = NT, + typename Functor +> +NT simple_mc_polytope_integrate(Functor Fx, + Polytope &P, + int N = 10000, + volumetype voltype = SOB, + int walk_length = 1, + NT e = 0.1, + Point Origin = pt) +{ + RNG rng(P.dimension()); + return simple_mc_polytope_integrate(Fx, P, rng, N, voltype, + walk_length, e, Origin); +} + // Simple MC Integration over Hyper-Rectangles template < @@ -179,36 +201,37 @@ template typename NT = NT, typename Functor > -NT simple_mc_integrate (Functor Fx, - int dim, - int N = 10000, - volumetype voltype = SOB, - Limit LowLimit = lt, - Limit UpLimit = lt, - int walk_length = 10, - NT e = 0.1) +NT simple_mc_integrate(Functor Fx, + int dim, + RNG &rng, + int N = 10000, + volumetype voltype = SOB, + Limit LowLimit = lt, + Limit UpLimit = lt, + int walk_length = 10, + NT e = 0.1) { // Setting up integration limits Point LL, UL; - if (LowLimit.size() == 1 && UpLimit.size() == 1 && LowLimit[0] == 0 && UpLimit[0] == 0) { - initiate_unit_limits(LL, UL, dim); - } else if (LowLimit.size() == UpLimit.size() && LowLimit.size() == dim) { - LL = init_limit (LowLimit, dim); - UL = init_limit (UpLimit, dim); - } else { - std::cerr << "Invalid limits entered"; - return -1; + if (LowLimit.size() == 1 && UpLimit.size() == 1 && LowLimit[0] == 0 && UpLimit[0] == 0) { + initiate_unit_limits(LL, UL, dim); + } else if (LowLimit.size() == UpLimit.size() && LowLimit.size() == dim) { + LL = init_limit (LowLimit, dim); + UL = init_limit (UpLimit, dim); + } else { + std::cerr << "Invalid limits entered"; + return -1; } - + NT sum = 0; if (valid_limits(LL, UL)) { // Creating an MT & VT for HPolytope(Hyper-Rectangle) for integration limits using LL & UL - MT mt(dim*2, dim); + MT mt(dim*2, dim); mt.setZero(); - VT vt(dim*2); + VT vt(dim*2); vt.setZero(); for (int i=0; i (Fx, P, N, voltype, walk_length, e); + NT integration_value = simple_mc_polytope_integrate (Fx, P, rng, N, voltype, walk_length, e); return integration_value; } else { @@ -231,4 +254,23 @@ NT simple_mc_integrate (Functor Fx, } } +template +< + typename WalkType = BallWalk, + typename RNG = RandomNumberGenerator, + typename NT = NT, + typename Functor +> +NT simple_mc_integrate(Functor Fx, + int dim, + int N = 10000, + volumetype voltype = SOB, + Limit LowLimit = lt, + Limit UpLimit = lt, + int walk_length = 10, + NT e = 0.1) +{ + RNG rng(dim); + return simple_mc_integrate(Fx, dim, rng, N, voltype, LowLimit, UpLimit, walk_length, e); +} #endif diff --git a/test/simple_mc_integration.cpp b/test/simple_mc_integration.cpp index ef3e60ddd..ca633f8f6 100644 --- a/test/simple_mc_integration.cpp +++ b/test/simple_mc_integration.cpp @@ -25,265 +25,300 @@ template NT exp_normsq(Point X) { - return exp(-X.squared_length()) ; + return exp(-X.squared_length()) ; } template NT simple_polynomial_1D(Point X) { - return (X[0] - 1) * (X[0] - 2) * (X[0] - 3); + return (X[0] - 1) * (X[0] - 2) * (X[0] - 3); } template NT logx_natural_1D(Point X) { - return log(X[0]); + return log(X[0]); } template NT rooted_squaresum(Point X) { - return sqrt(X.squared_length()); + return sqrt(X.squared_length()); } template NT one_sqsum(Point X) { - return 1 - X.squared_length(); + return 1 - X.squared_length(); } template void test_values (NT computed, NT expected, NT exact) { - std::cout << "Computed integration value = " << computed << std::endl; - std::cout << "Expected integration value = " << expected << std::endl; - std::cout << "Exact integration value = " << exact << std::endl; - std::cout << "Relative error (expected) = " << std::abs((computed - expected)/expected) << std::endl; - std::cout << "Relative error (exact) = " << std::abs((computed - exact)/exact) << std::endl ; + std::cout << "Computed integration value = " << computed << std::endl; + std::cout << "Expected integration value = " << expected << std::endl; + std::cout << "Exact integration value = " << exact << std::endl; + std::cout << "Relative error (expected) = " << std::abs((computed - expected)/expected) << std::endl; + std::cout << "Relative error (exact) = " << std::abs((computed - exact)/exact) << std::endl ; CHECK(((std::abs((computed - expected)/expected) < 0.00001) || (std::abs((computed - exact)/exact) < 0.2))); } template void call_test_simple_mc_integration_over_rectangles() { - typedef Cartesian Kernel; - typedef typename Kernel::Point Point; - typedef HPolytope HPOLYTOPE; - typedef VPolytope VPOLYTOPE; - typedef boost::mt19937 RNGType; - typedef BoostRandomNumberGenerator RandomNumberGenerator; - - NT integration_value; - std::cout << "\nTESTS FOR SIMPLE MC INTEGRATION OVER RECTANGLES USING UNIFORM RANDOM WALKS\n"; + typedef Cartesian Kernel; + typedef typename Kernel::Point Point; + typedef HPolytope HPOLYTOPE; + typedef VPolytope VPOLYTOPE; + typedef boost::mt19937 RNGType; + typedef BoostRandomNumberGenerator RandomNumberGenerator; - Limit LL{-1}; - Limit UL{6}; - integration_value = simple_mc_integrate (simple_polynomial_1D, 1, 100000, CB, LL, UL); - test_values(integration_value, 39.7, 40.25); + std::cout << "\nTESTS FOR SIMPLE MC INTEGRATION OVER RECTANGLES USING UNIFORM RANDOM WALKS\n"; - Limit LL1{0.5}; - Limit UL1{10}; - integration_value = simple_mc_integrate (logx_natural_1D, 1, 1000, CB, LL1, UL1); - test_values(integration_value, 13.65, 13.872); + NT integration_value; + RandomNumberGenerator rng; - Limit LL2{-1, -1}; - Limit UL2{1, 1}; - integration_value = simple_mc_integrate (rooted_squaresum, 2, 1000, SOB, LL2, UL2); - test_values(integration_value, 2.99, 3.0607); + Limit LL{-1}; + Limit UL{6}; + rng = RandomNumberGenerator(1); + integration_value = simple_mc_integrate (simple_polynomial_1D, 1, rng, 100000, CB, LL, UL); + test_values(integration_value, 39.7, 40.25); - integration_value = simple_mc_integrate (exp_normsq, 5, 1000, SOB); - test_values(integration_value, 7.49, 7.46); + Limit LL1{0.5}; + Limit UL1{10}; + rng = RandomNumberGenerator(1); + integration_value = simple_mc_integrate (logx_natural_1D, 1, rng, 1000, CB, LL1, UL1); + test_values(integration_value, 13.65, 13.872); - integration_value = simple_mc_integrate (exp_normsq, 8, 1000, SOB); - test_values(integration_value, 24.8, 24.76); + Limit LL2{-1, -1}; + Limit UL2{1, 1}; + rng = RandomNumberGenerator(2); + integration_value = simple_mc_integrate (rooted_squaresum, 2, rng, 1000, SOB, LL2, UL2); + test_values(integration_value, 2.99, 3.0607); - integration_value = simple_mc_integrate (exp_normsq, 10, 10000, SOB); - test_values(integration_value, 54.8, 55.25); + rng = RandomNumberGenerator(5); + integration_value = simple_mc_integrate (exp_normsq, 5, rng, 1000, SOB); + test_values(integration_value, 7.49, 7.46); + + rng = RandomNumberGenerator(8); + integration_value = simple_mc_integrate (exp_normsq, 8, rng, 1000, SOB); + test_values(integration_value, 24.8, 24.76); + + rng = RandomNumberGenerator(10); + integration_value = simple_mc_integrate (exp_normsq, 10, rng, 10000, SOB); + test_values(integration_value, 54.8, 55.25); } template void call_test_simple_mc_integration_over_cubes() { - typedef Cartesian Kernel; - typedef typename Kernel::Point Point; - typedef HPolytope HPOLYTOPE; - typedef VPolytope VPOLYTOPE; - typedef boost::mt19937 RNGType; - typedef BoostRandomNumberGenerator RandomNumberGenerator; - - std::cout << "\nTESTS FOR SIMPLE MC INTEGRATION OVER CUBES USING UNIFORM RANDOM WALKS\n"; - - NT integration_value; - HPOLYTOPE HP; - - HP = generate_cube (2, false); - integration_value = simple_mc_polytope_integrate (exp_normsq, HP, 1000, SOB, 10, 0.01); - test_values(integration_value, 2.20, 2.230); - - // For 2D Polytope shifted to (1,1) from origin - std::vector Origin{1, 1}; - Point newOrigin(2, Origin); - integration_value = simple_mc_polytope_integrate (exp_normsq, HP, 1000, SOB, 1, 0.01, newOrigin); - test_values(integration_value, 0.78, 0.777); - - HP = generate_cube (10, false); - integration_value = simple_mc_polytope_integrate (exp_normsq, HP, 10000, SOB); - test_values(integration_value, 54.7, 55.25); - - HP = generate_cube (15, false); - integration_value = simple_mc_polytope_integrate (exp_normsq, HP, 10000, SOB); - test_values(integration_value, 405.9, 410.690); - - HP = generate_cube (20, false); - integration_value = simple_mc_polytope_integrate (exp_normsq, HP, 10000, SOB); - test_values(integration_value, 3050.0, 3052.71); - - // Reading a H-Polytope from *.ine file for 20 Dimensions - // std::string fileName("cube10.ine"); - // std::ifstream inp; - // std::vector> Pin; - // inp.open(fileName, std::ifstream::in); - // read_pointset(inp,Pin); - // HPOLYTOPE HP(Pin); - // integration_value = simple_mc_polytope_integrate (exp_normsq, 2, HP, 1000, SOB); - // std::cout << "Integration value: " << integration_value << std::endl; - // test_values(integration_value, expected, exact); - // inp.close(); + typedef Cartesian Kernel; + typedef typename Kernel::Point Point; + typedef HPolytope HPOLYTOPE; + typedef VPolytope VPOLYTOPE; + typedef boost::mt19937 RNGType; + typedef BoostRandomNumberGenerator RandomNumberGenerator; + + std::cout << "\nTESTS FOR SIMPLE MC INTEGRATION OVER CUBES USING UNIFORM RANDOM WALKS\n"; + + NT integration_value; + HPOLYTOPE HP; + RandomNumberGenerator rng; + + HP = generate_cube (2, false); + rng = RandomNumberGenerator(HP.dimension()); + integration_value = simple_mc_polytope_integrate (exp_normsq, HP, rng, 1000, SOB, 10, 0.01); + test_values(integration_value, 2.20, 2.230); + + // For 2D Polytope shifted to (1,1) from origin + std::vector Origin{1, 1}; + Point newOrigin(2, Origin); + integration_value = simple_mc_polytope_integrate (exp_normsq, HP, rng, 1000, SOB, 1, 0.01, newOrigin); + test_values(integration_value, 0.78, 0.777); + + HP = generate_cube (10, false); + rng = RandomNumberGenerator(HP.dimension()); + integration_value = simple_mc_polytope_integrate (exp_normsq, HP, rng, 10000, SOB); + test_values(integration_value, 54.7, 55.25); + + HP = generate_cube (15, false); + rng = RandomNumberGenerator(HP.dimension()); + integration_value = simple_mc_polytope_integrate (exp_normsq, HP, rng, 10000, SOB); + test_values(integration_value, 405.9, 410.690); + + HP = generate_cube (20, false); + rng = RandomNumberGenerator(HP.dimension()); + integration_value = simple_mc_polytope_integrate (exp_normsq, HP, rng, 10000, SOB); + test_values(integration_value, 3050.0, 3052.71); + + // Reading a H-Polytope from *.ine file for 20 Dimensions + // std::string fileName("cube10.ine"); + // std::ifstream inp; + // std::vector> Pin; + // inp.open(fileName, std::ifstream::in); + // read_pointset(inp,Pin); + // HPOLYTOPE HP(Pin); + // integration_value = simple_mc_polytope_integrate (exp_normsq, 2, HP, rng, 1000, SOB); + // std::cout << "Integration value: " << integration_value << std::endl; + // test_values(integration_value, expected, exact); + // inp.close(); } template void call_test_simple_mc_integration_over_simplices() { - typedef Cartesian Kernel; - typedef typename Kernel::Point Point; - typedef HPolytope HPOLYTOPE; - typedef VPolytope VPOLYTOPE; - typedef boost::mt19937 RNGType; - typedef BoostRandomNumberGenerator RandomNumberGenerator; + typedef Cartesian Kernel; + typedef typename Kernel::Point Point; + typedef HPolytope HPOLYTOPE; + typedef VPolytope VPOLYTOPE; + typedef boost::mt19937 RNGType; + typedef BoostRandomNumberGenerator RandomNumberGenerator; + + std::cout << "\nTESTS FOR SIMPLE MC INTEGRATION OVER SIMPLICES USING UNIFORM RANDOM WALKS\n"; - std::cout << "\nTESTS FOR SIMPLE MC INTEGRATION OVER SIMPLICES USING UNIFORM RANDOM WALKS\n"; + NT integration_value; + HPOLYTOPE HP; + RandomNumberGenerator rng; - NT integration_value; - HPOLYTOPE HP; + HP = generate_simplex (1, false); + rng = RandomNumberGenerator(HP.dimension()); + integration_value = simple_mc_polytope_integrate (one_sqsum, HP, rng, 1000, CB, 10, 0.01); + test_values(integration_value, 0.67, 0.666); - HP = generate_simplex (1, false); - integration_value = simple_mc_polytope_integrate (one_sqsum, HP, 1000, CB, 10, 0.01); - test_values(integration_value, 0.67, 0.666); - - HP = generate_simplex (2, false); - integration_value = simple_mc_polytope_integrate (one_sqsum, HP, 1000, SOB, 10, 0.01); - test_values(integration_value, 0.34, 0.333); + HP = generate_simplex (2, false); + rng = RandomNumberGenerator(HP.dimension()); + integration_value = simple_mc_polytope_integrate (one_sqsum, HP, rng, 1000, SOB, 10, 0.01); + test_values(integration_value, 0.34, 0.333); - HP = generate_simplex (3, false); - integration_value = simple_mc_polytope_integrate (one_sqsum, HP, 1000, SOB); - test_values(integration_value, 0.116, 0.1166); + HP = generate_simplex (3, false); + rng = RandomNumberGenerator(HP.dimension()); + integration_value = simple_mc_polytope_integrate (one_sqsum, HP, rng, 1000, SOB); + test_values(integration_value, 0.116, 0.1166); - HP = generate_simplex (5, false); - integration_value = simple_mc_polytope_integrate (one_sqsum, HP, 1000, SOB); - test_values(integration_value, 0.00656, 0.0063492); + HP = generate_simplex (5, false); + rng = RandomNumberGenerator(HP.dimension()); + integration_value = simple_mc_polytope_integrate (one_sqsum, HP, rng, 1000, SOB); + test_values(integration_value, 0.00656, 0.0063492); - HP = generate_simplex (7, false); - integration_value = simple_mc_polytope_integrate (one_sqsum, HP, 10000, SOB); - test_values(integration_value, 0.000159, 0.000159832); + HP = generate_simplex (7, false); + rng = RandomNumberGenerator(HP.dimension()); + integration_value = simple_mc_polytope_integrate (one_sqsum, HP, rng, 10000, SOB); + test_values(integration_value, 0.000159, 0.000159832); } template void call_test_simple_mc_integration_over_product_simplices() { - typedef Cartesian Kernel; - typedef typename Kernel::Point Point; - typedef HPolytope HPOLYTOPE; - typedef VPolytope VPOLYTOPE; - typedef boost::mt19937 RNGType; - typedef BoostRandomNumberGenerator RandomNumberGenerator; + typedef Cartesian Kernel; + typedef typename Kernel::Point Point; + typedef HPolytope HPOLYTOPE; + typedef VPolytope VPOLYTOPE; + typedef boost::mt19937 RNGType; + typedef BoostRandomNumberGenerator RandomNumberGenerator; - std::cout << "\nTESTS FOR SIMPLE MC INTEGRATION OVER PRODUCT SIMPLICES USING UNIFORM RANDOM WALKS\n"; + std::cout << "\nTESTS FOR SIMPLE MC INTEGRATION OVER PRODUCT SIMPLICES USING UNIFORM RANDOM WALKS\n"; - NT integration_value; - HPOLYTOPE HP; + NT integration_value; + HPOLYTOPE HP; + RandomNumberGenerator rng; - HP = generate_prod_simplex (1, false); - integration_value = simple_mc_polytope_integrate (one_sqsum, HP, 1000, CB, 10, 0.01); - test_values(integration_value, 0.334, 0.333); - - HP = generate_prod_simplex (2, false); - integration_value = simple_mc_polytope_integrate (one_sqsum, HP, 1000, SOB); - test_values(integration_value, 0.0834, 0.0833); + HP = generate_prod_simplex (1, false); + rng = RandomNumberGenerator(HP.dimension()); + integration_value = simple_mc_polytope_integrate (one_sqsum, HP, rng, 1000, CB, 10, 0.01); + test_values(integration_value, 0.334, 0.333); - HP = generate_prod_simplex (3, false); - integration_value = simple_mc_polytope_integrate (one_sqsum, HP, 1000, SOB); - test_values(integration_value, 0.0110, 0.01111); + HP = generate_prod_simplex (2, false); + rng = RandomNumberGenerator(HP.dimension()); + integration_value = simple_mc_polytope_integrate (one_sqsum, HP, rng, 1000, SOB); + test_values(integration_value, 0.0834, 0.0833); - HP = generate_prod_simplex (5, false); - integration_value = simple_mc_polytope_integrate (one_sqsum, HP, 10000, SOB); - test_values(integration_value, 0.36e-4, 0.36375e-4); + HP = generate_prod_simplex (3, false); + rng = RandomNumberGenerator(HP.dimension()); + integration_value = simple_mc_polytope_integrate (one_sqsum, HP, rng, 1000, SOB); + test_values(integration_value, 0.0110, 0.01111); - HP = generate_prod_simplex (7, false); - integration_value = simple_mc_polytope_integrate (one_sqsum, HP, 10000, SOB); - test_values(integration_value, 0.235e-7, 0.24079e-7); + HP = generate_prod_simplex (5, false); + rng = RandomNumberGenerator(HP.dimension()); + integration_value = simple_mc_polytope_integrate (one_sqsum, HP, rng, 10000, SOB); + test_values(integration_value, 0.36e-4, 0.36375e-4); + + HP = generate_prod_simplex (7, false); + rng = RandomNumberGenerator(HP.dimension()); + integration_value = simple_mc_polytope_integrate (one_sqsum, HP, rng, 10000, SOB); + test_values(integration_value, 0.235e-7, 0.24079e-7); } template void call_test_simple_mc_integration_over_cross_polytopes() { - typedef Cartesian Kernel; - typedef typename Kernel::Point Point; - typedef HPolytope HPOLYTOPE; - typedef VPolytope VPOLYTOPE; - typedef boost::mt19937 RNGType; - typedef BoostRandomNumberGenerator RandomNumberGenerator; + typedef Cartesian Kernel; + typedef typename Kernel::Point Point; + typedef HPolytope HPOLYTOPE; + typedef VPolytope VPOLYTOPE; + typedef boost::mt19937 RNGType; + typedef BoostRandomNumberGenerator RandomNumberGenerator; + + std::cout << "\nTESTS FOR SIMPLE MC INTEGRATION OVER CROSS POLYTOPES USING UNIFORM RANDOM WALKS\n"; - std::cout << "\nTESTS FOR SIMPLE MC INTEGRATION OVER CROSS POLYTOPES USING UNIFORM RANDOM WALKS\n"; + NT integration_value; + HPOLYTOPE HP; + RandomNumberGenerator rng; - NT integration_value; - HPOLYTOPE HP; + HP = generate_cross (1, false); + rng = RandomNumberGenerator(HP.dimension()); + integration_value = simple_mc_polytope_integrate (one_sqsum, HP, rng, 1000, CB, 10, 0.01); + test_values(integration_value, 1.334, 1.333333); - HP = generate_cross (1, false); - integration_value = simple_mc_polytope_integrate (one_sqsum, HP, 1000, CB, 10, 0.01); - test_values(integration_value, 1.334, 1.333333); - - HP = generate_cross (2, false); - integration_value = simple_mc_polytope_integrate (one_sqsum, HP, 1000, SOB, 10, 0.01); - test_values(integration_value, 1.334, 1.33333); + HP = generate_cross (2, false); + rng = RandomNumberGenerator(HP.dimension()); + integration_value = simple_mc_polytope_integrate (one_sqsum, HP, rng, 1000, SOB, 10, 0.01); + test_values(integration_value, 1.334, 1.33333); - HP = generate_cross (3, false); - integration_value = simple_mc_polytope_integrate (one_sqsum, HP, 1000, SOB); - test_values(integration_value, 0.935000, 0.933333); + HP = generate_cross (3, false); + rng = RandomNumberGenerator(HP.dimension()); + integration_value = simple_mc_polytope_integrate (one_sqsum, HP, rng, 1000, SOB); + test_values(integration_value, 0.935000, 0.933333); - HP = generate_cross (5, false); - integration_value = simple_mc_polytope_integrate (one_sqsum, HP, 1000, SOB); - test_values(integration_value, 0.200000, 0.203174); + HP = generate_cross (5, false); + rng = RandomNumberGenerator(HP.dimension()); + integration_value = simple_mc_polytope_integrate (one_sqsum, HP, rng, 1000, SOB); + test_values(integration_value, 0.200000, 0.203174); - HP = generate_cross (7, false); - integration_value = simple_mc_polytope_integrate (one_sqsum, HP, 10000, SOB); - test_values(integration_value, 0.020000, 0.020458); + HP = generate_cross (7, false); + rng = RandomNumberGenerator(HP.dimension()); + integration_value = simple_mc_polytope_integrate (one_sqsum, HP, rng, 10000, SOB); + test_values(integration_value, 0.020000, 0.020458); } template void call_test_simple_mc_integration_over_birkhoff_polytopes() { - typedef Cartesian Kernel; - typedef typename Kernel::Point Point; - typedef HPolytope HPOLYTOPE; - typedef VPolytope VPOLYTOPE; - typedef boost::mt19937 RNGType; - typedef BoostRandomNumberGenerator RandomNumberGenerator; + typedef Cartesian Kernel; + typedef typename Kernel::Point Point; + typedef HPolytope HPOLYTOPE; + typedef VPolytope VPOLYTOPE; + typedef boost::mt19937 RNGType; + typedef BoostRandomNumberGenerator RandomNumberGenerator; + + std::cout << "\nTESTS FOR SIMPLE MC INTEGRATION OVER BIRKHOFF POLYTOPES USING UNIFORM RANDOM WALKS\n"; - std::cout << "\nTESTS FOR SIMPLE MC INTEGRATION OVER BIRKHOFF POLYTOPES USING UNIFORM RANDOM WALKS\n"; + NT integration_value; + HPOLYTOPE HP; + RandomNumberGenerator rng; - NT integration_value; - HPOLYTOPE HP; + HP = generate_birkhoff (2); + rng = RandomNumberGenerator(HP.dimension()); + integration_value = simple_mc_polytope_integrate (one_sqsum, HP, rng, 1000, CB, 10, 0.01); + test_values(integration_value, 0.67, 0.6666); - HP = generate_birkhoff (2); - integration_value = simple_mc_polytope_integrate (one_sqsum, HP, 1000, CB, 10, 0.01); - test_values(integration_value, 0.67, 0.6666); + HP = generate_birkhoff (3); + rng = RandomNumberGenerator(HP.dimension()); + integration_value = simple_mc_polytope_integrate (one_sqsum, HP, rng, 1000, SOB); + test_values(integration_value, 0.0470, 0.04722); - HP = generate_birkhoff (3); - integration_value = simple_mc_polytope_integrate (one_sqsum, HP, 1000, SOB); - test_values(integration_value, 0.0470, 0.04722); - - HP = generate_birkhoff (4); - integration_value = simple_mc_polytope_integrate (one_sqsum, HP, 10000, SOB); - test_values(integration_value, 0.000150, 0.000164); + HP = generate_birkhoff (4); + rng = RandomNumberGenerator(HP.dimension()); + integration_value = simple_mc_polytope_integrate (one_sqsum, HP, rng, 10000, SOB); + test_values(integration_value, 0.000150, 0.000164); } @@ -300,13 +335,13 @@ TEST_CASE("simplex") { } TEST_CASE("prod_simplex") { - call_test_simple_mc_integration_over_product_simplices(); + call_test_simple_mc_integration_over_product_simplices(); } TEST_CASE("cross") { - call_test_simple_mc_integration_over_cross_polytopes(); + call_test_simple_mc_integration_over_cross_polytopes(); } TEST_CASE("birkhoff") { - call_test_simple_mc_integration_over_birkhoff_polytopes(); + call_test_simple_mc_integration_over_birkhoff_polytopes(); } From fbc420612a901bf3aaa44bd8fa80e48f40128f40 Mon Sep 17 00:00:00 2001 From: Vissarion Fisikopoulos Date: Wed, 16 Nov 2022 21:59:10 +0200 Subject: [PATCH 14/20] Update README.md (#252) --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 459396a02..d5346d419 100644 --- a/README.md +++ b/README.md @@ -13,9 +13,10 @@ [![CRAN check](https://cranchecks.info/badges/worst/volesti)](https://cran.r-project.org/web/checks/check_results_volesti.html) [![CircleCI master](https://circleci.com/gh/GeomScale/volesti/tree/master.svg?style=shield)](https://circleci.com/gh/GeomScale/volesti/tree/master) [![CircleCI develop](https://circleci.com/gh/GeomScale/volesti/tree/develop.svg?style=shield)](https://circleci.com/gh/GeomScale/volesti/tree/develop) -[![gcc-test](https://github.com/GeomScale/volesti/workflows/gcc-test/badge.svg)](https://github.com/GeomScale/volesti/actions?query=workflow%3Agcc-test) -[![clang-test](https://github.com/GeomScale/volesti/workflows/clang-test/badge.svg)](https://github.com/GeomScale/volesti/actions?query=workflow%3Aclang-test) +[![gcc-test](https://github.com/GeomScale/volesti/actions/workflows/cmake-gcc.yml/badge.svg)](https://github.com/GeomScale/volesti/actions/workflows/cmake-gcc.yml?query=branch%3Adevelop) +[![clang-test](https://github.com/GeomScale/volesti/actions/workflows/cmake-clang.yml/badge.svg)](https://github.com/GeomScale/volesti/actions/workflows/cmake-clang.yml?query=branch%3Adevelop) [![codecov](https://codecov.io/gh/GeomScale/volesti/branch/develop/graph/badge.svg)](https://codecov.io/gh/GeomScale/volesti) +[![doc-actions](https://github.com/GeomScale/volesti/actions/workflows/docs.yml/badge.svg)](https://github.com/GeomScale/volesti/actions/workflows/docs.yml?query=branch%3Adevelop) [![R-CMD-ubuntu](https://github.com/GeomScale/volesti/workflows/R-CMD-check-ubuntu/badge.svg)](https://github.com/GeomScale/volesti/actions?query=workflow%3AR-CMD-ubuntu) [![R-CMD-macOS](https://github.com/GeomScale/volesti/workflows/R-CMD-check-macOS/badge.svg)](https://github.com/GeomScale/volesti/actions?query=workflow%3AR-CMD-macOS) From 82d138340256a2b8a2b7f98e648e247350a72d8f Mon Sep 17 00:00:00 2001 From: AlexManochis <62110146+AlexManochis@users.noreply.github.com> Date: Fri, 18 Nov 2022 11:33:00 +0200 Subject: [PATCH 15/20] Basic c++ documentation addition (#253) --- include/cartesian_geom/cartesian_kernel.h | 2 + include/cartesian_geom/point.h | 2 + include/convex_bodies/ball.h | 5 ++- include/convex_bodies/ballintersectconvex.h | 16 ++++--- include/convex_bodies/convex_body.h | 2 + .../correlation_matrices/corre_matrix.hpp | 3 +- .../correlation_spectrahedron.hpp | 2 +- .../correlation_spectrahedron_MT.hpp | 4 +- include/convex_bodies/ellipsoid.h | 3 +- include/convex_bodies/hpolytope.h | 1 + include/convex_bodies/orderpolytope.h | 3 +- .../spectrahedra/spectrahedron.h | 6 +-- include/convex_bodies/vpolyintersectvpoly.h | 6 ++- include/convex_bodies/vpolytope.h | 4 +- include/convex_bodies/zonoIntersecthpoly.h | 4 +- include/convex_bodies/zpolytope.h | 8 ++-- include/generators/convex_bodies_generator.h | 6 +++ include/generators/h_polytopes_generator.h | 3 ++ .../generators/known_polytope_generators.h | 19 +++++++- include/generators/order_polytope_generator.h | 8 ++-- include/generators/sdp_generator.h | 9 ++-- include/generators/v_polytopes_generators.h | 7 ++- include/generators/z_polytopes_generators.h | 11 ++++- include/lp_oracles/misc_lp.h | 6 ++- .../matrix_operations/EigenvaluesProblems.h | 2 +- include/misc/poset.h | 2 +- include/nlp_oracles/nlp_hpolyoracles.hpp | 37 +++++++++++----- include/nlp_oracles/nlp_vpolyoracles.hpp | 19 ++++++-- include/optimization/simulated_annealing.hpp | 2 +- include/preprocess/crhmc/crhmc_input.h | 4 +- include/preprocess/crhmc/crhmc_problem.h | 5 +++ include/preprocess/crhmc/opts.h | 4 ++ include/preprocess/crhmc/two_sided_barrier.h | 2 + .../crhmc/weighted_two_sided_barrier.h | 2 + .../crhmc/additional_units/auto_tuner.hpp | 6 +-- .../additional_units/dynamic_regularizer.hpp | 6 ++- .../additional_units/dynamic_step_size.hpp | 4 +- .../crhmc/additional_units/dynamic_weight.hpp | 4 +- include/random_walks/crhmc/hamiltonian.hpp | 3 ++ .../ellipsoid_walks/dikin_walker.h | 13 +++--- .../ellipsoid_walks/john_walker.h | 18 ++++---- .../ellipsoid_walks/vaidya_walker.h | 6 ++- include/root_finders/newton_raphson.hpp | 3 ++ include/sampling/mmcs.hpp | 44 +++++++++---------- include/sampling/parallel_mmcs.hpp | 42 +++++++++--------- 45 files changed, 246 insertions(+), 122 deletions(-) diff --git a/include/cartesian_geom/cartesian_kernel.h b/include/cartesian_geom/cartesian_kernel.h index 2b4679b93..3e1049b29 100644 --- a/include/cartesian_geom/cartesian_kernel.h +++ b/include/cartesian_geom/cartesian_kernel.h @@ -24,6 +24,8 @@ #include "point.h" +/// This class represents a cartesian kernel parameterized by a numerical type e.g. double +/// \tparam K Numerical Type template class Cartesian { diff --git a/include/cartesian_geom/point.h b/include/cartesian_geom/point.h index 532404a0f..a2209f4f5 100644 --- a/include/cartesian_geom/point.h +++ b/include/cartesian_geom/point.h @@ -13,6 +13,8 @@ #include #include +/// This class manipulates a point parameterized by a number type e.g. double +/// \tparam K Numerical Type template class point { diff --git a/include/convex_bodies/ball.h b/include/convex_bodies/ball.h index d28db837c..51dc26478 100644 --- a/include/convex_bodies/ball.h +++ b/include/convex_bodies/ball.h @@ -14,9 +14,10 @@ #include -// ball type +/// This class represents a ball parameterized by a point type +/// \tparam Point Point Type template -struct Ball{ +class Ball{ public: typedef Point PointType; typedef typename Point::FT NT; diff --git a/include/convex_bodies/ballintersectconvex.h b/include/convex_bodies/ballintersectconvex.h index 726e94cfb..12965d08c 100644 --- a/include/convex_bodies/ballintersectconvex.h +++ b/include/convex_bodies/ballintersectconvex.h @@ -12,7 +12,9 @@ #ifndef BALLINTERSECTCONVEX_H #define BALLINTERSECTCONVEX_H - +/// This class represents a polytope intersected with a ball +/// \tparam Polytope Polytope Type +/// \tparam CBall Ball Type template class BallIntersectPolytope { private: @@ -35,7 +37,7 @@ class BallIntersectPolytope { { return P.InnerBall(); } - + MT get_mat() const { return P.get_mat(); } @@ -135,9 +137,9 @@ class BallIntersectPolytope { { std::pair polypair = P.line_first_positive_intersect(r, v, Ar, Av, params); std::pair ball_lambda = B.line_positive_intersect(r, v); - + params.hit_ball = (polypair.first < ball_lambda.first) ? false : true; - int facet = params.hit_ball ? P.num_of_hyperplanes() : polypair.second; + int facet = params.hit_ball ? P.num_of_hyperplanes() : polypair.second; params.facet_prev = polypair.second; return std::pair(std::min(polypair.first, ball_lambda.first), facet); @@ -156,7 +158,7 @@ class BallIntersectPolytope { std::pair ball_lambda = B.line_positive_intersect(r, v); params.hit_ball = (polypair.first < ball_lambda.first) ? false : true; - int facet = params.hit_ball ? P.num_of_hyperplanes() : polypair.second; + int facet = params.hit_ball ? P.num_of_hyperplanes() : polypair.second; params.facet_prev = polypair.second; return std::pair(std::min(polypair.first, ball_lambda.first), facet); @@ -172,9 +174,9 @@ class BallIntersectPolytope { { std::pair polypair = P.line_positive_intersect(r, v, Ar, Av, lambda_prev, params); std::pair ball_lambda = B.line_positive_intersect(r, v); - + params.hit_ball = (polypair.first < ball_lambda.first) ? false : true; - int facet = params.hit_ball ? P.num_of_hyperplanes() : polypair.second; + int facet = params.hit_ball ? P.num_of_hyperplanes() : polypair.second; params.facet_prev = polypair.second; return std::pair(std::min(polypair.first, ball_lambda.first), facet); diff --git a/include/convex_bodies/convex_body.h b/include/convex_bodies/convex_body.h index f91ef87d1..e70e9e663 100644 --- a/include/convex_bodies/convex_body.h +++ b/include/convex_bodies/convex_body.h @@ -7,6 +7,8 @@ #include #include +/// This class represents a general convex body parameterized by a point type +/// \tparam Point Point type template class ConvexBody { public: diff --git a/include/convex_bodies/correlation_matrices/corre_matrix.hpp b/include/convex_bodies/correlation_matrices/corre_matrix.hpp index d8d8142ad..23f4ecbe3 100755 --- a/include/convex_bodies/correlation_matrices/corre_matrix.hpp +++ b/include/convex_bodies/correlation_matrices/corre_matrix.hpp @@ -12,8 +12,7 @@ /// This class handles the PointType used by CorreSpectra_MT class. /// Every point is a correlation matrix and only the lower triangular part is stored. - -/// @tparam NT +/// @tparam NT Number Type template class CorreMatrix{ public: diff --git a/include/convex_bodies/correlation_matrices/correlation_spectrahedron.hpp b/include/convex_bodies/correlation_matrices/correlation_spectrahedron.hpp index 275ad604a..a615b33c0 100755 --- a/include/convex_bodies/correlation_matrices/correlation_spectrahedron.hpp +++ b/include/convex_bodies/correlation_matrices/correlation_spectrahedron.hpp @@ -42,7 +42,7 @@ struct Precompute{ /// This class handles the spectrahedra of correlation matrices /// The PointType here is stored as vector. /// For the matrix PointType class, refer to CorrelationSpectrahedron_MT - +/// @tparam Point Point Type template class CorrelationSpectrahedron : public Spectrahedron{ public: diff --git a/include/convex_bodies/correlation_matrices/correlation_spectrahedron_MT.hpp b/include/convex_bodies/correlation_matrices/correlation_spectrahedron_MT.hpp index 9c7abe583..d3f754a5a 100755 --- a/include/convex_bodies/correlation_matrices/correlation_spectrahedron_MT.hpp +++ b/include/convex_bodies/correlation_matrices/correlation_spectrahedron_MT.hpp @@ -11,9 +11,9 @@ #define VOLESTI_CONVEX_BODIES_CORRELATION_MATRICES_VOLESTI_CORRELATION_SPECTRAHEDRON_MT_HPP #include "convex_bodies/correlation_matrices/corre_matrix.hpp" -// -/// This class handles the spectrahedra of correlation matrices +/// This class handles the spectrahedra of correlation matrices +/// @tparam CorreMatrix The Correlation Matrix template class CorrelationSpectrahedron_MT : public Spectrahedron{ public: diff --git a/include/convex_bodies/ellipsoid.h b/include/convex_bodies/ellipsoid.h index 3d4267193..18c7570c5 100644 --- a/include/convex_bodies/ellipsoid.h +++ b/include/convex_bodies/ellipsoid.h @@ -18,7 +18,8 @@ #include #include "volume/math_helpers.hpp" - +/// This class represents an ellipsoid parameterized by a point type +/// \tparam Point Point type template class Ellipsoid{ public: diff --git a/include/convex_bodies/hpolytope.h b/include/convex_bodies/hpolytope.h index 97d03788c..49d942827 100644 --- a/include/convex_bodies/hpolytope.h +++ b/include/convex_bodies/hpolytope.h @@ -39,6 +39,7 @@ bool is_inner_point_nan_inf(VT const& p) /// This class describes a polytope in H-representation or an H-polytope /// i.e. a polytope defined by a set of linear inequalities +/// \tparam Point Point type template class HPolytope { public: diff --git a/include/convex_bodies/orderpolytope.h b/include/convex_bodies/orderpolytope.h index 658b4360b..66854234b 100644 --- a/include/convex_bodies/orderpolytope.h +++ b/include/convex_bodies/orderpolytope.h @@ -19,7 +19,8 @@ #include "lp_oracles/solve_lp.h" #endif - +/// This class represents an order polytope parameterized by a point type +/// \tparam Point Point type template class OrderPolytope { public: diff --git a/include/convex_bodies/spectrahedra/spectrahedron.h b/include/convex_bodies/spectrahedra/spectrahedron.h index 22467ee0c..e8f341382 100644 --- a/include/convex_bodies/spectrahedra/spectrahedron.h +++ b/include/convex_bodies/spectrahedra/spectrahedron.h @@ -57,10 +57,8 @@ struct PrecomputationOfValues { }; -/// This class manipulates a spectrahedron, described by a LMI -/// \tparam NT Numeric Type -/// \tparam MT Matrix Type -/// \tparam VT Vector Type +/// This class manipulates a spectrahedron, described by a Linear Matrix Inequality i.e. LMI +/// \tparam Point Point Type template class Spectrahedron { public: diff --git a/include/convex_bodies/vpolyintersectvpoly.h b/include/convex_bodies/vpolyintersectvpoly.h index 31a5b27d4..a6dd97caf 100644 --- a/include/convex_bodies/vpolyintersectvpoly.h +++ b/include/convex_bodies/vpolyintersectvpoly.h @@ -17,7 +17,9 @@ #include #include "sampling/sphere.hpp" - +/// This class represents the intersection of two V-polytopes +/// \tparam VPolytope VPolytope Type +/// \tparam RNGType RNGType Type template class IntersectionOfVpoly { public: @@ -399,7 +401,7 @@ class IntersectionOfVpoly { void resetFlags() {} void update_position_internal(NT&){} - + void compute_reflection (Point &v, const Point &p, const int &facet) const { if (facet == 1) { diff --git a/include/convex_bodies/vpolytope.h b/include/convex_bodies/vpolytope.h index e22ff9d36..82ca66891 100644 --- a/include/convex_bodies/vpolytope.h +++ b/include/convex_bodies/vpolytope.h @@ -20,7 +20,9 @@ #include -// V-Polytope class +/// This class describes a polytope in V-representation or an V-polytope +/// i.e. a polytope defined as a convex combination of points +/// \tparam Point Point type template class VPolytope { public: diff --git a/include/convex_bodies/zonoIntersecthpoly.h b/include/convex_bodies/zonoIntersecthpoly.h index f7043f290..bbad43a68 100644 --- a/include/convex_bodies/zonoIntersecthpoly.h +++ b/include/convex_bodies/zonoIntersecthpoly.h @@ -10,7 +10,9 @@ #ifndef ZONOINTERSECTHPOLY_H #define ZONOINTERSECTHPOLY_H - +/// This class represents the intersection of a Zonotope with an H-polytope +/// \tparam Zonotope Zonotope Type +/// \tparam HPolytope HPolytope Type template class ZonoIntersectHPoly { private: diff --git a/include/convex_bodies/zpolytope.h b/include/convex_bodies/zpolytope.h index 3ecc4d427..1ad8868ea 100644 --- a/include/convex_bodies/zpolytope.h +++ b/include/convex_bodies/zpolytope.h @@ -19,6 +19,8 @@ #include "lp_oracles/vpolyoracles.h" #include "lp_oracles/zpolyoracles.h" +/// This class describes a zonotope i.e. the Minkowski sum of a set of line segments +/// \tparam Point Point type template class Zonotope { public: @@ -74,7 +76,7 @@ class Zonotope { //row = (REAL *) malloc((V.rows()+1) * sizeof(*row)); //colno_mem = (int *) malloc((V.rows()) * sizeof(*colno_mem)); //row_mem = (REAL *) malloc((V.rows()) * sizeof(*row_mem)); - + compute_eigenvectors(V.transpose()); }*/ @@ -482,7 +484,7 @@ class Zonotope { { return line_intersect_coord(r, rand_coord, lamdas); } - + //------------------------------oracles for exponential sampling---------------////// @@ -582,7 +584,7 @@ class Zonotope { a *= (-2.0 * v.dot(a)); v += a; } - + void resetFlags() {} void update_position_internal(NT&){} diff --git a/include/generators/convex_bodies_generator.h b/include/generators/convex_bodies_generator.h index 99a73fefe..f80b98d16 100644 --- a/include/generators/convex_bodies_generator.h +++ b/include/generators/convex_bodies_generator.h @@ -16,6 +16,8 @@ using std::isnan; #endif +/// This function generates a unit ball of given dimension +/// @tparam ConvexBody Type of returned Convex Body template ConvexBody generate_unit_ball(unsigned int dim) { @@ -40,6 +42,8 @@ ConvexBody generate_unit_ball(unsigned int dim) { return ConvexBody(unit_ball_funcs, unit_ball_grads, dim); } +/// This function generates a unit ball of given dimension intersected by a hyperplane +/// @tparam ConvexBody Type of returned Convex Body template ConvexBody generate_unit_ball_intersect_hyperplane(unsigned int dim) { @@ -74,6 +78,8 @@ ConvexBody generate_unit_ball_intersect_hyperplane(unsigned int dim) { return ConvexBody(unit_ball_funcs, unit_ball_grads, dim); } +/// This function generates a unit ball of given dimension intersected by a logsum exponential function +/// @tparam ConvexBody Type of returned Convex Body template ConvexBody generate_unit_ball_intersect_logsumexp(unsigned int dim) { diff --git a/include/generators/h_polytopes_generator.h b/include/generators/h_polytopes_generator.h index b01393b1e..dae44bdca 100644 --- a/include/generators/h_polytopes_generator.h +++ b/include/generators/h_polytopes_generator.h @@ -15,6 +15,9 @@ using std::isnan; #endif +/// This function generates a random H-polytope of given dimension and number of hyperplanes $m$ +/// @tparam Polytope Type of returned polytope +/// @tparam RNGType RNGType Type template Polytope random_hpoly(unsigned int dim, unsigned int m, double seed = std::numeric_limits::signaling_NaN()) { diff --git a/include/generators/known_polytope_generators.h b/include/generators/known_polytope_generators.h index e53121f3c..050918ad0 100644 --- a/include/generators/known_polytope_generators.h +++ b/include/generators/known_polytope_generators.h @@ -13,7 +13,9 @@ #include "convex_bodies/hpolytope.h" #include "convex_bodies/vpolytope.h" - +/// This function generates a hypercube of given dimension +/// The result can be either in V-representation (Vpoly=true) or in H-representation (V-poly-false) +/// @tparam Polytope Type of returned polytope template Polytope generate_cube(const unsigned int& dim, const bool& Vpoly) { @@ -75,6 +77,9 @@ Polytope generate_cube(const unsigned int& dim, const bool& Vpoly) { } +/// This function generates a crosspolytope of given dimension +/// The result can be either in V-representation (Vpoly=true) or in H-representation (V-poly-false) +/// @tparam Polytope Type of returned polytope template Polytope generate_cross(const unsigned int &dim, const bool &Vpoly) { @@ -135,6 +140,9 @@ Polytope generate_cross(const unsigned int &dim, const bool &Vpoly) { } +/// This function generates a simplex of given dimension +/// The result can be either in V-representation (Vpoly=true) or in H-representation (V-poly-false) +/// @tparam Polytope Type of returned polytope template Polytope generate_simplex(const unsigned int &dim, const bool &Vpoly){ typedef typename Polytope::MT MT; @@ -172,6 +180,9 @@ Polytope generate_simplex(const unsigned int &dim, const bool &Vpoly){ } +/// This function generates a product of simplices of given dimension +/// The result can be either in V-representation (Vpoly=true) or in H-representation (V-poly-false) +/// @tparam Polytope Type of returned polytope template Polytope generate_prod_simplex(const unsigned int &dim, bool Vpoly = false){ @@ -245,6 +256,9 @@ Polytope generate_prod_simplex(const unsigned int &dim, bool Vpoly = false){ } +/// This function generates a skinny cube of given dimension +/// The result can be either in V-representation (Vpoly=true) or in H-representation (V-poly-false) +/// @tparam Polytope Type of returned polytope template Polytope generate_skinny_cube(const unsigned int &dim, bool Vpoly = false) { @@ -299,6 +313,9 @@ Polytope generate_skinny_cube(const unsigned int &dim, bool Vpoly = false) { return Polytope(dim, A, b); } +/// This function generates the Birkhoff polytope of given type n +/// The Birkhoff polytope also called the assignment polytope or the polytope of doubly stochastic matrices. +/// @tparam Polytope Type of returned polytope template Polytope generate_birkhoff(unsigned int const& n) { diff --git a/include/generators/order_polytope_generator.h b/include/generators/order_polytope_generator.h index 19dae9943..bfece556e 100644 --- a/include/generators/order_polytope_generator.h +++ b/include/generators/order_polytope_generator.h @@ -38,8 +38,9 @@ static const std::unordered_map instances = }; -// generates an Order Polytope from the instance name provided among the -// possible instances in the map above. +// generates an Order Polytope from an instance name +// Instances taken from: https://github.com/ttalvitie/le-counting-practice +/// @tparam Polytope Type of returned polytope template Polytope generate_orderpoly(std::string& instance_name) { std::stringstream in_ss(instances.at(instance_name)); @@ -47,7 +48,8 @@ Polytope generate_orderpoly(std::string& instance_name) { return Polytope(poset); } -// generates a cube as an Order Polytope +// Generates a cube as an Order Polytope +/// @tparam Polytope Type of returned polytope template Polytope generate_cube_orderpoly(unsigned int dim) { typedef typename Poset::RV RV; diff --git a/include/generators/sdp_generator.h b/include/generators/sdp_generator.h index 9348f24b0..c2b3a1547 100644 --- a/include/generators/sdp_generator.h +++ b/include/generators/sdp_generator.h @@ -10,7 +10,8 @@ typedef boost::mt19937 RNGType; - +/// Generates a random matrix +/// @tparam NT Number type template void randomMatrixGOE(Eigen::Matrix& M) { typedef Eigen::Matrix MT; @@ -28,7 +29,8 @@ void randomMatrixGOE(Eigen::Matrix& M) { } } -// m must be even +/// Generates a random spectahedron S(n, m) +/// @tparam NT Number type template Spectrahedron, Eigen::Matrix > generateSDP(int n, int m) { typedef Eigen::Matrix MT; @@ -83,7 +85,8 @@ Spectrahedron, Eigen::Matr //return optimization::sdp_problem(spectrahedron, obj); } - +/// Generates a random spectahedron S(n, m) +/// @tparam NT Number type template Spectrahedron, Eigen::Matrix > generateSDP2(int n, int m) { diff --git a/include/generators/v_polytopes_generators.h b/include/generators/v_polytopes_generators.h index 2cb349c1e..3977e9489 100644 --- a/include/generators/v_polytopes_generators.h +++ b/include/generators/v_polytopes_generators.h @@ -26,6 +26,9 @@ void removeRow(MT &matrix, unsigned int rowToRemove) matrix.conservativeResize(numRows,numCols); } +/// Generates a random V-polytope +/// @tparam Polytope polytope type +/// @tparam RNGType RNGType type template Polytope random_vpoly(unsigned int dim, unsigned int k, double seed = std::numeric_limits::signaling_NaN()) { @@ -74,7 +77,9 @@ Polytope random_vpoly(unsigned int dim, unsigned int k, double seed = std::numer return Polytope(dim, V, b); } - +/// Generates a random V-polytope inside a cube +/// @tparam Polytope polytope type +/// @tparam RNGType RNGType type template Polytope random_vpoly_incube(unsigned int d, unsigned int k, double seed = std::numeric_limits::signaling_NaN()) { diff --git a/include/generators/z_polytopes_generators.h b/include/generators/z_polytopes_generators.h index af9c572e0..8afbc6d11 100644 --- a/include/generators/z_polytopes_generators.h +++ b/include/generators/z_polytopes_generators.h @@ -14,6 +14,9 @@ using std::isnan; #endif +/// Generates a random Zonotope with generators draw from Gaussian distribution +/// @tparam Polytope polytope type +/// @tparam RNGType RNGType type template Polytope gen_zonotope_gaussian(int dim, int m, double seed = std::numeric_limits::signaling_NaN()) { @@ -56,6 +59,9 @@ Polytope gen_zonotope_gaussian(int dim, int m, double seed = std::numeric_limits } +/// Generates a random Zonotope with generators draw from uniform distribution +/// @tparam Polytope polytope type +/// @tparam RNGType RNGType type template Polytope gen_zonotope_uniform(int dim, int m, double seed = std::numeric_limits::signaling_NaN()) { @@ -88,10 +94,13 @@ Polytope gen_zonotope_uniform(int dim, int m, double seed = std::numeric_limits< Polytope P(dim, A, b); return P; - + } +/// Generates a random Zonotope with generators draw from exponential distribution +/// @tparam Polytope polytope type +/// @tparam RNGType RNGType type template Polytope gen_zonotope_exponential(int dim, int m, double seed = std::numeric_limits::signaling_NaN()) { diff --git a/include/lp_oracles/misc_lp.h b/include/lp_oracles/misc_lp.h index bbbbd92f4..9e8e2528c 100644 --- a/include/lp_oracles/misc_lp.h +++ b/include/lp_oracles/misc_lp.h @@ -10,7 +10,11 @@ #include "lp_lib.h" -// compute the chebychev ball of an H-polytope described by a dxd matrix A and d-dimensional vector b, s.t.: Ax<=b +// Computes the Chebychev ball of an H-polytope described by a dxd matrix A and d-dimensional vector b, s.t.: Ax<=b +/// @tparam NT Number type +/// @tparam Point Point type +/// @tparam MT Matrix type +/// @tparam VT Vector type template std::pair ComputeChebychevBall(MT &A, VT &b){ diff --git a/include/matrix_operations/EigenvaluesProblems.h b/include/matrix_operations/EigenvaluesProblems.h index 8a22408b0..4012177f3 100644 --- a/include/matrix_operations/EigenvaluesProblems.h +++ b/include/matrix_operations/EigenvaluesProblems.h @@ -37,7 +37,7 @@ class EigenvaluesProblems { /// A specialization of the template class EigenvaluesProblems for dense Eigen matrices and vectors. -/// \tparam NT +/// \tparam NT Numer Type template class EigenvaluesProblems, Eigen::Matrix > { public: diff --git a/include/misc/poset.h b/include/misc/poset.h index 08296ff18..69ba02ec7 100644 --- a/include/misc/poset.h +++ b/include/misc/poset.h @@ -15,7 +15,7 @@ #include #include - +/// A class to represent a partial order set aka Poset class Poset { public: typedef std::pair RT; // relation type diff --git a/include/nlp_oracles/nlp_hpolyoracles.hpp b/include/nlp_oracles/nlp_hpolyoracles.hpp index 13db29f0d..d7394ca2b 100644 --- a/include/nlp_oracles/nlp_hpolyoracles.hpp +++ b/include/nlp_oracles/nlp_hpolyoracles.hpp @@ -75,7 +75,9 @@ using namespace ifopt; -// Define the variable t we use in the optimization +/// Define the variable t we use in the optimization +/// \tparam VT Vector Type +/// \tparam NT Numeric Type template class HPolyOracleVariables : public VariableSet { public: @@ -104,7 +106,9 @@ class HPolyOracleVariables : public VariableSet { }; -// Define the cost function f(t) = t (ipopt takes minimization so it is -t) +/// Define the cost function f(t) = t (ipopt takes minimization so it is -t) +/// \tparam VT Vector Type +/// \tparam NT Numeric Type template class HPolyOracleCost : public CostTerm { public: @@ -128,8 +132,12 @@ class HPolyOracleCost : public CostTerm { }; -// Define the feasibility constraint A p(t) <= b which we translate -// to (A * C) * Phi <= b +/// Define the feasibility constraint A p(t) <= b which we translate +/// to (A * C) * Phi <= b +/// \tparam MT Matrix Type +/// \tparam VT Vector Type +/// \tparam NT Numeric Type +/// \tparam bfunc feasibility constraint type template class HPolyOracleFeasibility : public ConstraintSet { public: @@ -211,6 +219,9 @@ class HPolyOracleFeasibility : public ConstraintSet { }; +/// Oracle that uses the COIN-OR ipopt solver +/// \tparam Polytope Polytope Type +/// \tparam bfunc feasibility constraint type template struct IpoptHPolyoracle { typedef typename Polytope::MT MT; @@ -340,9 +351,11 @@ struct IpoptHPolyoracle { }; -// Compute intersection of H-polytope P := Ax <= b -// with polynomial curve p(t) = sum a_j (t - t0)^j -// Uses the MPsolve library +/// Compute intersection of H-polytope P := Ax <= b +/// with polynomial curve p(t) = sum a_j (t - t0)^j +/// Uses the MPsolve library +/// \tparam Polytope Polytope Type +/// \tparam bfunc feasibility constraint type template struct MPSolveHPolyoracle { @@ -437,10 +450,12 @@ struct MPSolveHPolyoracle { }; -// Compute intersection of H-polytope P := Ax <= b -// with curve p(t) = sum a_j phi_j(t) where phi_j are basis -// functions (e.g. polynomials) -// Uses Newton-Raphson to solve the transcendental equation +/// Compute intersection of H-polytope P := Ax <= b +/// with curve p(t) = sum a_j phi_j(t) where phi_j are basis +/// functions (e.g. polynomials) +/// Uses Newton-Raphson to solve the transcendental equation +/// \tparam Polytope Polytope Type +/// \tparam bfunc feasibility constraint type template struct NewtonRaphsonHPolyoracle { typedef typename Polytope::MT MT; diff --git a/include/nlp_oracles/nlp_vpolyoracles.hpp b/include/nlp_oracles/nlp_vpolyoracles.hpp index ead3d28f5..9e921d9c3 100644 --- a/include/nlp_oracles/nlp_vpolyoracles.hpp +++ b/include/nlp_oracles/nlp_vpolyoracles.hpp @@ -44,7 +44,9 @@ using namespace ifopt; -// Define the variable t we use in the optimization +/// Define the variable t we use in the optimization +/// \tparam VT Vector Type +/// \tparam MT Matrix Type template class VPolyOracleVariableT : public VariableSet { public: @@ -73,7 +75,9 @@ class VPolyOracleVariableT : public VariableSet { }; -// Define the variable t we use in the optimization +/// Define the variable t we use in the optimization +/// \tparam VT Vector Type +/// \tparam MT Matrix Type template class VPolyOracleVariableLambdas : public VariableSet { public: @@ -102,7 +106,9 @@ class VPolyOracleVariableLambdas : public VariableSet { }; -// Define the cost function f(t) = t (ipopt takes minimization so it is -t) +/// Define the cost function f(t) = t (ipopt takes minimization so it is -t) +/// \tparam VT Vector Type +/// \tparam MT Matrix Type template class VPolyOracleCost : public CostTerm { public: @@ -127,6 +133,9 @@ class VPolyOracleCost : public CostTerm { }; +/// Define the feasibility lambdas +/// \tparam VT Vector Type +/// \tparam MT Matrix Type template class VPolyoracleFeasibilityLambdas : public ConstraintSet { public: @@ -232,7 +241,9 @@ class VPolyOracleFeasibilityCurve : public ConstraintSet { }; - +/// Oracle for V-polytopes +/// \tparam Polytope Polytope Type +/// \tparam bfunc feasibility constraint type template struct IpoptVPolyoracle { typedef typename Polytope::MT MT; diff --git a/include/optimization/simulated_annealing.hpp b/include/optimization/simulated_annealing.hpp index 5d1683acb..77e15b128 100644 --- a/include/optimization/simulated_annealing.hpp +++ b/include/optimization/simulated_annealing.hpp @@ -22,7 +22,7 @@ #define CONSTANT_1 20 /// Holds parameters of the algorithm -/// \tparam Point Class point +/// \tparam Point Point Type template struct SimulatedAnnealingSettings { /// The numeric type diff --git a/include/preprocess/crhmc/crhmc_input.h b/include/preprocess/crhmc/crhmc_input.h index 984bd339f..1a674f1e4 100644 --- a/include/preprocess/crhmc/crhmc_input.h +++ b/include/preprocess/crhmc/crhmc_input.h @@ -30,7 +30,9 @@ struct ZeroScalarFunctor using Type = typename Point::FT; Type operator()(Point const &x) const { return 0; } }; -/*Input structure: With this the user can define a polytope sampling problem*/ + +/// +/// Input structure: With this the user can define the input for a crhmc polytope sampling problem template , typename grad = ZeroFunctor, diff --git a/include/preprocess/crhmc/crhmc_problem.h b/include/preprocess/crhmc/crhmc_problem.h index 5a8a73be8..68ccb25e5 100644 --- a/include/preprocess/crhmc/crhmc_problem.h +++ b/include/preprocess/crhmc/crhmc_problem.h @@ -35,6 +35,11 @@ #define SIMD_LEN 0 #endif const size_t chol_k = (SIMD_LEN == 0) ? 1 : SIMD_LEN; + +/// +/// Crhmc sampling problem: With this the user can define a crhmc polytope sampling problem +/// @tparam Point Point type +/// @tparam Input Input format template class crhmc_problem { public: diff --git a/include/preprocess/crhmc/opts.h b/include/preprocess/crhmc/opts.h index dad3a49a5..df73d5a7c 100644 --- a/include/preprocess/crhmc/opts.h +++ b/include/preprocess/crhmc/opts.h @@ -13,8 +13,12 @@ // Yunbum Kook, Yin Tat Lee, Ruoqi Shen, Santosh S. Vempala. "Sampling with // Riemannian Hamiltonian // Monte Carlo in a Constrained Space" + #ifndef OPTS_H #define OPTS_H + +/// @brief Crhmc options +/// @tparam Type Numer type template class opts { public: /*Preprocess options*/ diff --git a/include/preprocess/crhmc/two_sided_barrier.h b/include/preprocess/crhmc/two_sided_barrier.h index 8afef162e..39b27bab9 100644 --- a/include/preprocess/crhmc/two_sided_barrier.h +++ b/include/preprocess/crhmc/two_sided_barrier.h @@ -23,6 +23,8 @@ #include "cartesian_geom/cartesian_kernel.h" #include +/// @brief A two sided barrier used by crhmc sampler +/// @tparam Point Point Type template class two_sided_barrier { using NT = typename Point::FT; diff --git a/include/preprocess/crhmc/weighted_two_sided_barrier.h b/include/preprocess/crhmc/weighted_two_sided_barrier.h index 9cfdab845..1bda5d3bf 100644 --- a/include/preprocess/crhmc/weighted_two_sided_barrier.h +++ b/include/preprocess/crhmc/weighted_two_sided_barrier.h @@ -23,6 +23,8 @@ #include "cartesian_geom/cartesian_kernel.h" #include +/// @brief A weighted two sided barrier used by crhmc sampler +/// @tparam Point Point Type template class weighted_two_sided_barrier { using NT = typename Point::FT; diff --git a/include/random_walks/crhmc/additional_units/auto_tuner.hpp b/include/random_walks/crhmc/additional_units/auto_tuner.hpp index 42afc0a77..0fc50e79a 100644 --- a/include/random_walks/crhmc/additional_units/auto_tuner.hpp +++ b/include/random_walks/crhmc/additional_units/auto_tuner.hpp @@ -19,9 +19,9 @@ #include "random_walks/crhmc/additional_units/dynamic_step_size.hpp" #include "random_walks/crhmc/additional_units/dynamic_weight.hpp" -/*This class is responsible for calling the additional modules for: -modifying the weights, ode step size and regularizer factor addaptively. -*/ +// This class is responsible for calling the additional crhmc modules for: +// modifying the weights, ode step size and regularizer factor addaptively. + template class auto_tuner { using weight_tuner = dynamic_weight; diff --git a/include/random_walks/crhmc/additional_units/dynamic_regularizer.hpp b/include/random_walks/crhmc/additional_units/dynamic_regularizer.hpp index ca213c5a9..9cd80b18d 100644 --- a/include/random_walks/crhmc/additional_units/dynamic_regularizer.hpp +++ b/include/random_walks/crhmc/additional_units/dynamic_regularizer.hpp @@ -16,8 +16,10 @@ #ifndef DYNAMIC_REGULARIZER_HPP #define DYNAMIC_REGULARIZER_HPP #include "Eigen/Eigen" -// Module for updating the extra term we add to the barrier -// This is nessecary for any polytope with free variables + +/// Module for updating the extra term we add to the barrier +/// This is nessecary for any polytope with free variables +/// Part of crhmc sampler template class dynamic_regularizer { public: diff --git a/include/random_walks/crhmc/additional_units/dynamic_step_size.hpp b/include/random_walks/crhmc/additional_units/dynamic_step_size.hpp index 6b224cc5d..ef1871731 100644 --- a/include/random_walks/crhmc/additional_units/dynamic_step_size.hpp +++ b/include/random_walks/crhmc/additional_units/dynamic_step_size.hpp @@ -15,7 +15,9 @@ // Monte Carlo in a Constrained Space" #ifndef DYNAMIC_STEP_SIZE_HPP #define DYNAMIC_STEP_SIZE_HPP -/*Module for dynamically choosing the ODE step size and the velocity momentum*/ + +/// Module for dynamically choosing the ODE step size and the velocity momentum +/// Part of crhmc sampler template class dynamic_step_size { using NT = typename Sampler::NT; diff --git a/include/random_walks/crhmc/additional_units/dynamic_weight.hpp b/include/random_walks/crhmc/additional_units/dynamic_weight.hpp index 52917aa5b..ce945216f 100644 --- a/include/random_walks/crhmc/additional_units/dynamic_weight.hpp +++ b/include/random_walks/crhmc/additional_units/dynamic_weight.hpp @@ -15,7 +15,9 @@ // Monte Carlo in a Constrained Space" #ifndef DYNAMIC_WEIGHT_HPP #define DYNAMIC_WEIGHT_HPP -/*Class responsible for updating the weights of the barrier*/ + +/// Class responsible for updating the weights of the barrier +/// Part of crhmc sampler template class dynamic_weight { using NT = typename Sampler::NT; diff --git a/include/random_walks/crhmc/hamiltonian.hpp b/include/random_walks/crhmc/hamiltonian.hpp index 6b02e097c..d8cb5a82e 100644 --- a/include/random_walks/crhmc/hamiltonian.hpp +++ b/include/random_walks/crhmc/hamiltonian.hpp @@ -20,6 +20,9 @@ #include "preprocess/crhmc/crhmc_utils.h" #include +/// @brief Class for the hamiltonian used in crhmc sampler +/// @tparam Polytope Polytope Type +/// @tparam Point Point Type template class Hamiltonian { using VT = typename Polytope::VT; diff --git a/include/random_walks/ellipsoid_walks/dikin_walker.h b/include/random_walks/ellipsoid_walks/dikin_walker.h index 273ff5984..b16d997b8 100644 --- a/include/random_walks/ellipsoid_walks/dikin_walker.h +++ b/include/random_walks/ellipsoid_walks/dikin_walker.h @@ -9,8 +9,8 @@ // Licensed under GNU LGPL.3, see LICENCE file -// The implemented random walk is presented in the paper of -// Y. Chen, R. Dwivedi, M. J. Wainwright and B. Yu, +// The implemented random walk is presented in the paper of +// Y. Chen, R. Dwivedi, M. J. Wainwright and B. Yu, // "Fast MCMC Sampling Algorithms on Polytopes", // Journal of Machine Learning Research, 2018. @@ -20,7 +20,8 @@ #include #include "math_functions.h" - +/// @brief Class that defines the Dikin walk sampler +/// @tparam Dtype Number Type template class DikinWalker { public: @@ -70,7 +71,7 @@ class DikinWalker { sample_gaussian(this->nb_dim_, 0., 1., gaussian_step); // get hessian - Eigen::Matrix new_sqrt_inv_hess = + Eigen::Matrix new_sqrt_inv_hess = Eigen::Matrix::Zero(this->nb_dim_, this->nb_dim_); sqrtInvHessBarrier(this->curr_sample_, new_sqrt_inv_hess); @@ -79,11 +80,11 @@ class DikinWalker { bool acceptRejectReverse(const Eigen::Matrix& new_sample){ // get hessian on x - Eigen::Matrix new_sqrt_inv_hess_x = + Eigen::Matrix new_sqrt_inv_hess_x = Eigen::Matrix::Zero(this->nb_dim_, this->nb_dim_); sqrtInvHessBarrier(this->curr_sample_, new_sqrt_inv_hess_x); // get hessian on y - Eigen::Matrix new_sqrt_inv_hess_y = + Eigen::Matrix new_sqrt_inv_hess_y = Eigen::Matrix::Zero(this->nb_dim_, this->nb_dim_); sqrtInvHessBarrier(new_sample, new_sqrt_inv_hess_y); diff --git a/include/random_walks/ellipsoid_walks/john_walker.h b/include/random_walks/ellipsoid_walks/john_walker.h index 0b68606fa..fd1d25f92 100644 --- a/include/random_walks/ellipsoid_walks/john_walker.h +++ b/include/random_walks/ellipsoid_walks/john_walker.h @@ -9,8 +9,8 @@ // Licensed under GNU LGPL.3, see LICENCE file -// The implemented random walk is presented in the paper of -// Y. Chen, R. Dwivedi, M. J. Wainwright and B. Yu, +// The implemented random walk is presented in the paper of +// Y. Chen, R. Dwivedi, M. J. Wainwright and B. Yu, // "Fast MCMC Sampling Algorithms on Polytopes", // Journal of Machine Learning Research, 2018. @@ -22,6 +22,8 @@ #include "math_functions.h" +/// @brief Class that defines the John walk sampler +/// @tparam Dtype Number Type template class JohnWalker { public: @@ -75,7 +77,7 @@ class JohnWalker { sample_gaussian(this->nb_dim_, 0., 1., gaussian_step); // get hessian - Eigen::Matrix new_sqrt_inv_hess = + Eigen::Matrix new_sqrt_inv_hess = Eigen::Matrix::Zero( this->nb_dim_, this->nb_dim_); sqrtInvHessBarrier(this->curr_sample_, new_sqrt_inv_hess); @@ -85,21 +87,21 @@ class JohnWalker { bool acceptRejectReverse(const Eigen::Matrix &new_sample) { // get hessian on y - Eigen::Matrix new_sqrt_inv_hess_y = + Eigen::Matrix new_sqrt_inv_hess_y = Eigen::Matrix::Zero( this->nb_dim_, this->nb_dim_); sqrtInvHessBarrier(new_sample, new_sqrt_inv_hess_y); // get hessian on x - Eigen::Matrix new_sqrt_inv_hess_x = + Eigen::Matrix new_sqrt_inv_hess_x = Eigen::Matrix::Zero( this->nb_dim_, this->nb_dim_); sqrtInvHessBarrier(this->curr_sample_, new_sqrt_inv_hess_x); Dtype scale = r_ / std::sqrt(Dtype(this->nb_dim_)); - Dtype p_y_to_x = gaussian_density(this->curr_sample_, new_sample, + Dtype p_y_to_x = gaussian_density(this->curr_sample_, new_sample, new_sqrt_inv_hess_y.inverse() / scale); - Dtype p_x_to_y = gaussian_density(new_sample, this->curr_sample_, + Dtype p_x_to_y = gaussian_density(new_sample, this->curr_sample_, new_sqrt_inv_hess_x.inverse() / scale); Dtype ar_ratio = std::min(1., p_y_to_x / p_x_to_y); @@ -194,7 +196,7 @@ class JohnWalker { Eigen::Matrix cons_b_; // Current vector Eigen::Matrix curr_sample_; - + Eigen::Matrix curr_weight_; }; diff --git a/include/random_walks/ellipsoid_walks/vaidya_walker.h b/include/random_walks/ellipsoid_walks/vaidya_walker.h index fd34f5002..6da8b5a74 100644 --- a/include/random_walks/ellipsoid_walks/vaidya_walker.h +++ b/include/random_walks/ellipsoid_walks/vaidya_walker.h @@ -9,8 +9,8 @@ // Licensed under GNU LGPL.3, see LICENCE file -// The implemented random walk is presented in the paper of -// Y. Chen, R. Dwivedi, M. J. Wainwright and B. Yu, +// The implemented random walk is presented in the paper of +// Y. Chen, R. Dwivedi, M. J. Wainwright and B. Yu, // "Fast MCMC Sampling Algorithms on Polytopes", // Journal of Machine Learning Research, 2018. @@ -21,6 +21,8 @@ #include "math_functions.h" +/// @brief Class that defines the Vaidya walk sampler +/// @tparam Dtype Number Type template class VaidyaWalker { public: diff --git a/include/root_finders/newton_raphson.hpp b/include/root_finders/newton_raphson.hpp index 6a91cd466..27411d767 100644 --- a/include/root_finders/newton_raphson.hpp +++ b/include/root_finders/newton_raphson.hpp @@ -11,6 +11,9 @@ #ifndef NEWTON_RAPHSON_HPP #define NEWTON_RAPHSON_HPP +/// @brief Function implementing the Newton-Raphson numerical method +/// @tparam NT Number type +/// @tparam func Function type template std::pair newton_raphson(NT t0, func f, func grad_f, const NT rtol, const NT reg=0, const unsigned int max_tries=1000000) { diff --git a/include/sampling/mmcs.hpp b/include/sampling/mmcs.hpp index 7f095a51e..07529ad6d 100644 --- a/include/sampling/mmcs.hpp +++ b/include/sampling/mmcs.hpp @@ -11,18 +11,18 @@ #include "diagnostics/ess_window_updater.hpp" /** - The class implements a single step of the Multiphase Monte Carlo Sampling algorithm - given in, - - A. Chalkis, V. Fisikopoulos, E. Tsigaridas, H. Zafeiropoulos, Geometric algorithms for sampling the flux space of metabolic networks, SoCG 21. - + * The class implements a single step of the Multiphase Monte Carlo Sampling algorithm + * given in, + * + * A. Chalkis, V. Fisikopoulos, E. Tsigaridas, H. Zafeiropoulos, Geometric algorithms for sampling the flux space of metabolic networks, SoCG 21. + * * @tparam Polytope convex polytope type * @tparam RandomNumberGenerator random number generator type * @tparam MT matrix type * @tparam Point cartensian point type * @tparam WalkTypePolicy random walk type */ -template +template < typename Polytope, typename RandomNumberGenerator, @@ -62,21 +62,21 @@ bool perform_mmcs_step(Polytope &P, Point p = starting_point; - if (request_rounding) + if (request_rounding) { TotalRandPoints.setZero(num_rounding_steps, P.dimension()); - } - else + } + else { TotalRandPoints.setZero(max_num_samples, P.dimension()); } - + Walk walk(P, p, rng, WalkType.param); ESSestimator estimator(window, P.dimension()); - walk.template parameters_burnin(P, p, 10 + int(std::log(NT(P.dimension()))), 10, rng); + walk.template parameters_burnin(P, p, 10 + int(std::log(NT(P.dimension()))), 10, rng); - while (!done) + while (!done) { walk.template get_starting_point(P, p, q, 10, rng); for (int i = 0; i < window; i++) @@ -86,37 +86,37 @@ bool perform_mmcs_step(Polytope &P, } estimator.update_estimator(winPoints); total_samples += window; - if (total_samples >= TotalRandPoints.rows()) + if (total_samples >= TotalRandPoints.rows()) { - if (total_samples > TotalRandPoints.rows()) + if (total_samples > TotalRandPoints.rows()) { TotalRandPoints.conservativeResize(total_samples, P.dimension()); } if (request_rounding || total_samples >= max_num_samples) - { + { done = true; } } TotalRandPoints.block(total_samples - window, 0, window, P.dimension()) = winPoints.transpose(); - if (done || total_samples >= points_to_sample) + if (done || total_samples >= points_to_sample) { - estimator.estimate_effective_sample_size(); + estimator.estimate_effective_sample_size(); min_eff_samples = int(estimator.get_effective_sample_size().minCoeff()); - if (done && min_eff_samples < target_ess) + if (done && min_eff_samples < target_ess) { Neff_sampled = min_eff_samples; return false; } - if (min_eff_samples >= target_ess) + if (min_eff_samples >= target_ess) { Neff_sampled = min_eff_samples; return true; } - if (min_eff_samples > 0) + if (min_eff_samples > 0) { points_to_sample += (total_samples / min_eff_samples) * (target_ess - min_eff_samples) + 100; - } - else + } + else { points_to_sample = total_samples + 100; } diff --git a/include/sampling/parallel_mmcs.hpp b/include/sampling/parallel_mmcs.hpp index fa0abbdaf..a8308f4ce 100644 --- a/include/sampling/parallel_mmcs.hpp +++ b/include/sampling/parallel_mmcs.hpp @@ -14,11 +14,11 @@ #include "diagnostics/ess_window_updater.hpp" /** - The class implements a single step of the Parallel Multiphase Monte Carlo Sampling algorithm - given in, - - A. Chalkis, V. Fisikopoulos, E. Tsigaridas, H. Zafeiropoulos, Geometric algorithms for sampling the flux space of metabolic networks, SoCG 21. - + * The class implements a single step of the Parallel Multiphase Monte Carlo Sampling algorithm + * given in, + * + * A. Chalkis, V. Fisikopoulos, E. Tsigaridas, H. Zafeiropoulos, Geometric algorithms for sampling the flux space of metabolic networks, SoCG 21. + * * @tparam WalkTypePolicy random walk type * @tparam Polytope convex polytope type * @tparam RandomNumberGenerator random number generator type @@ -26,7 +26,7 @@ * @tparam Point cartensian point type * @tparam NT number type */ -template +template < typename WalkTypePolicy, typename Polytope, @@ -71,7 +71,7 @@ bool perform_parallel_mmcs_step(Polytope &P, unsigned int jj = 0, d = P.dimension(), m = P.num_of_hyperplanes(); bool complete = false; - while (jj < nburns) + while (jj < nburns) { for (unsigned int i = 0; i < num_threads; i++) { @@ -97,17 +97,17 @@ bool perform_parallel_mmcs_step(Polytope &P, TotalRandPoints_per_thread[i].setZero(bound_on_num_points_per_thread[i], d); } unsigned int upper_bound_on_total_num_of_samples; - if (request_rounding) + if (request_rounding) { upper_bound_on_total_num_of_samples = num_rounding_steps; - } - else + } + else { upper_bound_on_total_num_of_samples = max_num_samples; } TotalRandPoints.resize(0, 0); Walk walk(P, L); - + _thread_parameters random_walk_parameters(d, m); walk.template parameters_burnin(P, pp, 10 + int(std::log(NT(d))), 10, rng, random_walk_parameters); Point const p = pp; @@ -117,7 +117,7 @@ bool perform_parallel_mmcs_step(Polytope &P, int thread_index = omp_get_thread_num(); _thread_parameters thread_random_walk_parameters(d, m); - for (unsigned int it = 0; it < num_starting_points_per_thread[thread_index]; it++) + for (unsigned int it = 0; it < num_starting_points_per_thread[thread_index]; it++) { if (done_all) { @@ -134,7 +134,7 @@ bool perform_parallel_mmcs_step(Polytope &P, { estimator.update_estimator(winPoints_per_thread[thread_index]); } - + num_generated_points_per_thread[thread_index] += window; #pragma omp critical @@ -152,25 +152,25 @@ bool perform_parallel_mmcs_step(Polytope &P, #pragma omp single { if (done || (total_samples >= points_to_sample)) - { + { estimator.estimate_effective_sample_size(); - + min_eff_samples = int(estimator.get_effective_sample_size().minCoeff()); - if (done && min_eff_samples < target_ess) + if (done && min_eff_samples < target_ess) { Neff_sampled = min_eff_samples; done_all = true; } - if (min_eff_samples >= target_ess) + if (min_eff_samples >= target_ess) { complete = true; Neff_sampled = min_eff_samples; done_all = true; } - if (min_eff_samples > 0 && !done_all) + if (min_eff_samples > 0 && !done_all) { points_to_sample += (total_samples / min_eff_samples) * (target_ess - min_eff_samples) + 100; - } + } else if (!done_all) { points_to_sample = total_samples + 100; @@ -180,10 +180,10 @@ bool perform_parallel_mmcs_step(Polytope &P, } } - estimator.estimate_effective_sample_size(); + estimator.estimate_effective_sample_size(); min_eff_samples = int(estimator.get_effective_sample_size().minCoeff()); Neff_sampled = min_eff_samples; - if (min_eff_samples >= target_ess) + if (min_eff_samples >= target_ess) { complete = true; } From 6b359f424f9f3075dab7737c6630267aa3df3257 Mon Sep 17 00:00:00 2001 From: Vissarion Fisikopoulos Date: Mon, 5 Dec 2022 11:10:47 +0200 Subject: [PATCH 16/20] Update CRAN badges (#255) Issue https://github.com/GeomScale/volesti/issues/254 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d5346d419..9e2d3fe43 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ ### 🧪 Test results -[![CRAN check](https://cranchecks.info/badges/worst/volesti)](https://cran.r-project.org/web/checks/check_results_volesti.html) +[![CRAN check](https://badges.cranchecks.info/worst/dplyr.svg)](https://cran.r-project.org/web/checks/check_results_volesti.html) [![CircleCI master](https://circleci.com/gh/GeomScale/volesti/tree/master.svg?style=shield)](https://circleci.com/gh/GeomScale/volesti/tree/master) [![CircleCI develop](https://circleci.com/gh/GeomScale/volesti/tree/develop.svg?style=shield)](https://circleci.com/gh/GeomScale/volesti/tree/develop) [![gcc-test](https://github.com/GeomScale/volesti/actions/workflows/cmake-gcc.yml/badge.svg)](https://github.com/GeomScale/volesti/actions/workflows/cmake-gcc.yml?query=branch%3Adevelop) From 423bbcfc9851b43acd62032c732d633f0d6cb01e Mon Sep 17 00:00:00 2001 From: Vissarion Fisikopoulos Date: Mon, 9 Jan 2023 15:06:27 +0200 Subject: [PATCH 17/20] Fix CRAN badges in README (#259) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9e2d3fe43..d4ea2bf54 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ ### 🧪 Test results -[![CRAN check](https://badges.cranchecks.info/worst/dplyr.svg)](https://cran.r-project.org/web/checks/check_results_volesti.html) +[![CRAN check](https://badges.cranchecks.info/worst/volesti.svg)](https://cran.r-project.org/web/checks/check_results_volesti.html) [![CircleCI master](https://circleci.com/gh/GeomScale/volesti/tree/master.svg?style=shield)](https://circleci.com/gh/GeomScale/volesti/tree/master) [![CircleCI develop](https://circleci.com/gh/GeomScale/volesti/tree/develop.svg?style=shield)](https://circleci.com/gh/GeomScale/volesti/tree/develop) [![gcc-test](https://github.com/GeomScale/volesti/actions/workflows/cmake-gcc.yml/badge.svg)](https://github.com/GeomScale/volesti/actions/workflows/cmake-gcc.yml?query=branch%3Adevelop) From 2b876b256a919446e08ccda260a68dfc5dbc26be Mon Sep 17 00:00:00 2001 From: Vissarion Fisikopoulos Date: Sat, 11 Feb 2023 20:19:19 +0100 Subject: [PATCH 18/20] Enable github actions to build examples. Avoid passing a polytope as a const reference. --- .github/workflows/cmake-clang.yml | 4 +- .github/workflows/cmake-examples.yml | 40 +++++++++++++ examples/hpolytope-volume/hpolytopeVolume.cpp | 2 +- examples/mmcs_method/CMakeLists.txt | 2 +- examples/multithread_sampling/CMakeLists.txt | 6 +- .../sampling_multithread_walks.cpp | 11 ++-- .../optimization_spectrahedra/CMakeLists.txt | 9 +-- .../sampler.cpp | 6 +- examples/vpolytope-volume/CMakeLists.txt | 4 +- examples/vpolytope-volume/vpolytopevolume.cpp | 2 +- include/convex_bodies/ballintersectconvex.h | 2 +- include/random_walks/boundary_cdhr_walk.hpp | 2 +- include/random_walks/boundary_rdhr_walk.hpp | 2 +- include/random_walks/compute_diameter.hpp | 4 +- ...ial_hamiltonian_monte_carlo_exact_walk.hpp | 26 ++++----- .../gaussian_accelerated_billiard_walk.hpp | 8 +-- include/random_walks/gaussian_ball_walk.hpp | 6 +- include/random_walks/gaussian_cdhr_walk.hpp | 4 +- ...ian_hamiltonian_monte_carlo_exact_walk.hpp | 26 ++++----- include/random_walks/gaussian_rdhr_walk.hpp | 4 +- include/random_walks/multithread_walks.hpp | 58 +++++++++---------- include/random_walks/uniform_ball_walk.hpp | 6 +- include/random_walks/uniform_cdhr_walk.hpp | 4 +- include/random_walks/uniform_rdhr_walk.hpp | 8 +-- include/sampling/random_point_generators.hpp | 10 ++-- include/volume/volume_cooling_balls.hpp | 2 +- include/volume/volume_cooling_gaussians.hpp | 10 ++-- include/volume/volume_cooling_hpoly.hpp | 4 +- include/volume/volume_sequence_of_balls.hpp | 4 +- 29 files changed, 158 insertions(+), 118 deletions(-) create mode 100644 .github/workflows/cmake-examples.yml diff --git a/.github/workflows/cmake-clang.yml b/.github/workflows/cmake-clang.yml index 5386c3963..caa22fff2 100644 --- a/.github/workflows/cmake-clang.yml +++ b/.github/workflows/cmake-clang.yml @@ -1,5 +1,5 @@ ############################################################################## -# GitHub Actions Workflow for volesti to build tests with GCC +# GitHub Actions Workflow for volesti to build tests with Clang # # Copyright (c) 2020-2022 Vissarion Fisikopoulos # @@ -36,4 +36,4 @@ jobs: cd build; cmake -D CMAKE_CXX_COMPILER=${{ matrix.config.compiler }} -D CMAKE_CXX_FLAGS=-fsanitize=memory -D CMAKE_CXX_FLAGS=-fsanitize=undefined -D CMAKE_CXX_FLAGS=-g -D DISABLE_NLP_ORACLES=ON -D USE_MKL=OFF ../test; make; - ctest --verbose; + ctest --verbose; \ No newline at end of file diff --git a/.github/workflows/cmake-examples.yml b/.github/workflows/cmake-examples.yml new file mode 100644 index 000000000..b7784fa30 --- /dev/null +++ b/.github/workflows/cmake-examples.yml @@ -0,0 +1,40 @@ +############################################################################## +# GitHub Actions Workflow for volesti to build tests with GCC +# +# Copyright (c) 2020-2022 Vissarion Fisikopoulos +# +# Licensed under GNU LGPL.3, see LICENCE file +############################################################################## +name: cmake-examples + +on: [push, pull_request] + +jobs: + build: + name: ${{ matrix.config.os }} - ${{ matrix.config.compiler }} + strategy: + fail-fast: false + matrix: + config: + - {os: ubuntu-22.04, compiler_pkg: clang-11, compiler: clang++-11} + - {os: ubuntu-22.04, compiler_pkg: g++-11, compiler: g++-11} + runs-on: ${{ matrix.config.os }} + steps: + - uses: actions/checkout@v1 + - run: sudo apt-get update || true; + sudo apt-get install ${{ matrix.config.compiler_pkg }} lp-solve libomp-dev libopenblas-dev libarpack2-dev; + - name: Build examples + run: | + cd examples + for dir in */; do + if [ "$dir" != "EnvelopeProblemSOS/" ] && [ "$dir" != "python_utilities/" ]; then + echo + echo "Building examples in $dir ....................." + cd "$dir" + mkdir build && cd build + cmake -DCMAKE_CXX_COMPILER=${{ matrix.config.compiler }} -DUSE_MKL=OFF .. + make + cd ../.. + fi + done + diff --git a/examples/hpolytope-volume/hpolytopeVolume.cpp b/examples/hpolytope-volume/hpolytopeVolume.cpp index 487ce98f4..b61190de9 100644 --- a/examples/hpolytope-volume/hpolytopeVolume.cpp +++ b/examples/hpolytope-volume/hpolytopeVolume.cpp @@ -29,7 +29,7 @@ typedef typename Kernel::Point Point; typedef BoostRandomNumberGenerator RNGType; typedef HPolytope HPOLYTOPE; -void calculateVolumes(const HPOLYTOPE &HP) { +void calculateVolumes(HPOLYTOPE &HP) { // Setup parameters for calculating volume int walk_len = 10 + HP.dimension()/10; NT e=0.1; diff --git a/examples/mmcs_method/CMakeLists.txt b/examples/mmcs_method/CMakeLists.txt index 1ee6ce0a5..01b8a040c 100644 --- a/examples/mmcs_method/CMakeLists.txt +++ b/examples/mmcs_method/CMakeLists.txt @@ -105,7 +105,7 @@ else () add_definitions(${CXX_COVERAGE_COMPILE_FLAGS} "-DBOOST_NO_AUTO_PTR") #add_definitions(${CXX_COVERAGE_COMPILE_FLAGS} "-lgslcblas") #add_definitions( "-O3 -lgsl -lm -ldl -lgslcblas" ) - + find_package(OpenMP REQUIRED) add_executable (skinny_cube_10_dim skinny_cube_10_dim.cpp) diff --git a/examples/multithread_sampling/CMakeLists.txt b/examples/multithread_sampling/CMakeLists.txt index fe4d5ee75..ded4b4dbb 100644 --- a/examples/multithread_sampling/CMakeLists.txt +++ b/examples/multithread_sampling/CMakeLists.txt @@ -97,7 +97,7 @@ else () endif () - add_definitions(${CMAKE_CXX_FLAGS} "-std=c++11") # enable C++11 standard + #add_definitions(${CMAKE_CXX_FLAGS} "-std=c++11") # enable C++11 standard add_definitions(${CMAKE_CXX_FLAGS} "-O3") # optimization of the compiler #add_definitions(${CXX_COVERAGE_COMPILE_FLAGS} "-lgsl") add_definitions(${CXX_COVERAGE_COMPILE_FLAGS} "-lm") @@ -105,11 +105,11 @@ else () add_definitions(${CXX_COVERAGE_COMPILE_FLAGS} "-DBOOST_NO_AUTO_PTR") #add_definitions(${CXX_COVERAGE_COMPILE_FLAGS} "-lgslcblas") #add_definitions( "-O3 -lgsl -lm -ldl -lgslcblas" ) - + find_package(OpenMP REQUIRED) add_executable (sampling_multithread_walks sampling_multithread_walks.cpp) - + TARGET_LINK_LIBRARIES(sampling_multithread_walks ${LP_SOLVE} OpenMP::OpenMP_CXX) diff --git a/examples/multithread_sampling/sampling_multithread_walks.cpp b/examples/multithread_sampling/sampling_multithread_walks.cpp index 191b8e6c5..cb416c72c 100644 --- a/examples/multithread_sampling/sampling_multithread_walks.cpp +++ b/examples/multithread_sampling/sampling_multithread_walks.cpp @@ -48,12 +48,12 @@ MT get_uniform_samples(Polytope &P, std::list randPoints; typedef RandomPointGeneratorMultiThread _RandomPointGeneratorMultiThread; - + _RandomPointGeneratorMultiThread::apply(P, p, N, walk_len, num_threads, randPoints, push_back_policy, rng); unsigned int d = P.dimension(); - + MT samples(d, N); unsigned int jj = 0; @@ -92,7 +92,7 @@ MT get_gaussian_samples(Polytope &P, std::list randPoints; typedef GaussianPointGeneratorMultiThread _GaussianPointGeneratorMultiThread; - + _GaussianPointGeneratorMultiThread::apply(P, p, a_i, N, walk_len, num_threads, randPoints, push_back_policy, rng); @@ -118,11 +118,10 @@ void test_uniform_random_walk(std::string random_walk, unsigned int const& num_t typedef Eigen::Matrix MT; typedef Eigen::Matrix VT; typedef BoostRandomNumberGenerator RNGType; - Hpolytope P; unsigned int d = 10, walk_len = 5, N = 5000; std::cout << "--- Sampling with " + random_walk + " walk from H-cube10" << std::endl; - P = generate_cube(d, false); + Hpolytope P = generate_cube(d, false); RNGType rng(P.dimension()); MT samples = get_uniform_samples(P, rng, walk_len, N, num_threads); @@ -155,7 +154,7 @@ void test_gaussian_random_walk(std::string random_walk, unsigned int const& num_ int main() { - + unsigned int num_threads = 2; test_uniform_random_walk("BRDHR", num_threads); diff --git a/examples/optimization_spectrahedra/CMakeLists.txt b/examples/optimization_spectrahedra/CMakeLists.txt index 356a3e6ac..a35aee4c7 100644 --- a/examples/optimization_spectrahedra/CMakeLists.txt +++ b/examples/optimization_spectrahedra/CMakeLists.txt @@ -78,11 +78,12 @@ IF (OPENBLAS_LIB) IF (GFORTRAN_LIB) message( STATUS "GFORTRAN_LIB found: ${GFORTRAN_LIB}" ) - add_executable (boltzmann_hmc_walk boltzmann_hmc_walk.cpp) - TARGET_LINK_LIBRARIES(boltzmann_hmc_walk ${ARPACK_LIB} ${LAPACK_LIBRARIES} ${GFORTRAN_LIB}) + # These are not compiling, see issue https://github.com/GeomScale/volesti/issues/264 + #add_executable (boltzmann_hmc_walk boltzmann_hmc_walk.cpp) + #TARGET_LINK_LIBRARIES(boltzmann_hmc_walk ${ARPACK_LIB} ${LAPACK_LIBRARIES} ${GFORTRAN_LIB}) - add_executable (solve_sdp solve_sdp.cpp) - TARGET_LINK_LIBRARIES(solve_sdp ${GFORTRAN_LIB} ${LAPACK_LIBRARIES} ${ARPACK_LIB}) + #add_executable (solve_sdp solve_sdp.cpp) + #TARGET_LINK_LIBRARIES(solve_sdp ${GFORTRAN_LIB} ${LAPACK_LIBRARIES} ${ARPACK_LIB}) ELSE() MESSAGE(STATUS "gfortran is required but it could not be found") diff --git a/examples/sampling-hpolytope-with-billiard-walks/sampler.cpp b/examples/sampling-hpolytope-with-billiard-walks/sampler.cpp index 16b6f2367..22dd6d9e5 100644 --- a/examples/sampling-hpolytope-with-billiard-walks/sampler.cpp +++ b/examples/sampling-hpolytope-with-billiard-walks/sampler.cpp @@ -37,7 +37,7 @@ void write_to_file(std::string filename, std::vector const& randPoints) { } -void sample_using_uniform_billiard_walk(HPOLYTOPE const& HP, RNGType& rng, unsigned int walk_len, unsigned int num_points) { +void sample_using_uniform_billiard_walk(HPOLYTOPE& HP, RNGType& rng, unsigned int walk_len, unsigned int num_points) { std::string filename = "uniform_billiard_walk.txt"; typedef RandomPointGenerator Generator; @@ -49,7 +49,7 @@ void sample_using_uniform_billiard_walk(HPOLYTOPE const& HP, RNGType& rng, unsig } -void sample_using_uniform_accelerated_billiard_walk(HPOLYTOPE const& HP, RNGType& rng, unsigned int walk_len, unsigned int num_points) { +void sample_using_uniform_accelerated_billiard_walk(HPOLYTOPE& HP, RNGType& rng, unsigned int walk_len, unsigned int num_points) { std::string filename = "uniform_accelerated_billiard_walk.txt"; typedef RandomPointGenerator Generator; @@ -61,7 +61,7 @@ void sample_using_uniform_accelerated_billiard_walk(HPOLYTOPE const& HP, RNGType } -void sample_using_gaussian_billiard_walk(HPOLYTOPE const& HP, RNGType& rng, unsigned int walk_len, unsigned int num_points) { +void sample_using_gaussian_billiard_walk(HPOLYTOPE& HP, RNGType& rng, unsigned int walk_len, unsigned int num_points) { std::string filename = "gaussian_billiard_walk.txt"; typedef MultivariateGaussianRandomPointGenerator Generator; diff --git a/examples/vpolytope-volume/CMakeLists.txt b/examples/vpolytope-volume/CMakeLists.txt index fdcb3095f..5ffd4784b 100644 --- a/examples/vpolytope-volume/CMakeLists.txt +++ b/examples/vpolytope-volume/CMakeLists.txt @@ -106,7 +106,7 @@ else () add_definitions(${CXX_COVERAGE_COMPILE_FLAGS} "-ldl") add_definitions(${CXX_COVERAGE_COMPILE_FLAGS} "-DBOOST_NO_AUTO_PTR") - add_executable (vpolytopeVolume vpolytopeVolume.cpp) - TARGET_LINK_LIBRARIES(vpolytopeVolume ${LP_SOLVE}) + add_executable (vpolytopevolume vpolytopevolume.cpp) + TARGET_LINK_LIBRARIES(vpolytopevolume ${LP_SOLVE}) endif() diff --git a/examples/vpolytope-volume/vpolytopevolume.cpp b/examples/vpolytope-volume/vpolytopevolume.cpp index e814b5875..007964232 100644 --- a/examples/vpolytope-volume/vpolytopevolume.cpp +++ b/examples/vpolytope-volume/vpolytopevolume.cpp @@ -28,7 +28,7 @@ typedef typename Kernel::Point Point; typedef BoostRandomNumberGenerator RNGType; typedef VPolytope VPOLYTOPE; -void calculateVolumes(const VPOLYTOPE &VP) { +void calculateVolumes(VPOLYTOPE &VP) { // Setup parameters for calculating volume int walk_len = 10 + VP.dimension()/10; NT e=0.1; diff --git a/include/convex_bodies/ballintersectconvex.h b/include/convex_bodies/ballintersectconvex.h index 12965d08c..b61ae5324 100644 --- a/include/convex_bodies/ballintersectconvex.h +++ b/include/convex_bodies/ballintersectconvex.h @@ -28,7 +28,7 @@ class BallIntersectPolytope { BallIntersectPolytope() {} - BallIntersectPolytope(Polytope const& PP, CBall &BB) : P(PP), B(BB) {}; + BallIntersectPolytope(Polytope& PP, CBall &BB) : P(PP), B(BB) {}; Polytope first() const { return P; } CBall second() const { return B; } diff --git a/include/random_walks/boundary_cdhr_walk.hpp b/include/random_walks/boundary_cdhr_walk.hpp index 40d35df2d..5e6b5224c 100644 --- a/include/random_walks/boundary_cdhr_walk.hpp +++ b/include/random_walks/boundary_cdhr_walk.hpp @@ -26,7 +26,7 @@ struct BCDHRWalk typedef typename Point::FT NT; template - Walk(GenericPolytope const& P, Point const& p, RandomNumberGenerator& rng) + Walk(GenericPolytope& P, Point const& p, RandomNumberGenerator& rng) { initialize(P, p, rng); } diff --git a/include/random_walks/boundary_rdhr_walk.hpp b/include/random_walks/boundary_rdhr_walk.hpp index 0cf582957..29d500b6c 100644 --- a/include/random_walks/boundary_rdhr_walk.hpp +++ b/include/random_walks/boundary_rdhr_walk.hpp @@ -27,7 +27,7 @@ struct BRDHRWalk typedef typename Point::FT NT; template - Walk(GenericPolytope const& P, Point const& p, RandomNumberGenerator& rng) + Walk(GenericPolytope& P, Point const& p, RandomNumberGenerator& rng) { initialize(P, p, rng); } diff --git a/include/random_walks/compute_diameter.hpp b/include/random_walks/compute_diameter.hpp index e3ec0f441..b20aa839a 100644 --- a/include/random_walks/compute_diameter.hpp +++ b/include/random_walks/compute_diameter.hpp @@ -205,7 +205,7 @@ template struct compute_diameter> { template - static NT compute(OrderPolytope const& P) + static NT compute(OrderPolytope& P) { return std::sqrt(NT(P.dimension())); } @@ -215,7 +215,7 @@ template struct compute_diameter, Ellipsoid > > { template - static NT compute(BallIntersectPolytope, Ellipsoid> const& P) + static NT compute(BallIntersectPolytope, Ellipsoid>& P) { NT polytope_diameter = std::sqrt(NT(P.dimension())); return std::min(polytope_diameter, (NT(2) * P.radius())); diff --git a/include/random_walks/exponential_hamiltonian_monte_carlo_exact_walk.hpp b/include/random_walks/exponential_hamiltonian_monte_carlo_exact_walk.hpp index 0d1199410..6e5d2e000 100644 --- a/include/random_walks/exponential_hamiltonian_monte_carlo_exact_walk.hpp +++ b/include/random_walks/exponential_hamiltonian_monte_carlo_exact_walk.hpp @@ -84,7 +84,7 @@ struct Walk < typename GenericPolytope > - inline bool apply(GenericPolytope const& P, + inline bool apply(GenericPolytope& P, Point& p, // a point to start unsigned int const& walk_length, RandomNumberGenerator &rng) @@ -104,7 +104,7 @@ struct Walk } T = rng.sample_urdist() * _Len; _v = GetDirection::apply(n, rng, false); - + it = 0; while (it < _rho) { @@ -122,7 +122,7 @@ struct Walk P.compute_reflection(_v, _p, pbpair.second); it++; } - + } while (P.is_in(_p, INSIDE_BODY_TOLLERANCE) == 0); if (it == _rho) { _p = p0; @@ -137,7 +137,7 @@ struct Walk < typename GenericPolytope > - inline void get_starting_point(GenericPolytope const& P, + inline void get_starting_point(GenericPolytope& P, Point const& center, Point &q, unsigned int const& walk_length, @@ -158,7 +158,7 @@ struct Walk < typename GenericPolytope > - inline void parameters_burnin(GenericPolytope const& P, + inline void parameters_burnin(GenericPolytope& P, Point const& center, unsigned int const& num_points, unsigned int const& walk_length, @@ -171,7 +171,7 @@ struct Walk pointset.push_back(_p); NT rad = NT(0), max_dist, Lmax = NT(0), radius = P.InnerBall().second; - for (int i = 0; i < num_points; i++) + for (int i = 0; i < num_points; i++) { p = GetPointInDsphere::apply(n, radius, rng); p += center; @@ -179,18 +179,18 @@ struct Walk apply(P, p, walk_length, rng); max_dist = get_max_distance(pointset, p, rad); - if (max_dist > Lmax) + if (max_dist > Lmax) { Lmax = max_dist; } - if (2.0 * rad > Lmax) + if (2.0 * rad > Lmax) { Lmax = 2.0 * rad; } pointset.push_back(p); } - if (Lmax > _Len) + if (Lmax > _Len) { update_delta(Lmax); } @@ -210,7 +210,7 @@ private : < typename GenericPolytope > - inline void initialize(GenericPolytope const& P, + inline void initialize(GenericPolytope& P, Point const& p, RandomNumberGenerator &rng) { @@ -219,7 +219,7 @@ private : _lambdas.setZero(P.num_of_hyperplanes()); _Av.setZero(P.num_of_hyperplanes()); _v = GetDirection::apply(n, rng, false); - + do { _p = p; T = rng.sample_urdist() * _Len; @@ -262,11 +262,11 @@ private : } - inline double get_max_distance(std::vector &pointset, Point const& q, double &rad) + inline double get_max_distance(std::vector &pointset, Point const& q, double &rad) { double dis = -1.0, temp_dis; int jj = 0; - for (auto vecit = pointset.begin(); vecit!=pointset.end(); vecit++, jj++) + for (auto vecit = pointset.begin(); vecit!=pointset.end(); vecit++, jj++) { temp_dis = (q.getCoefficients() - (*vecit).getCoefficients()).norm(); if (temp_dis > dis) { diff --git a/include/random_walks/gaussian_accelerated_billiard_walk.hpp b/include/random_walks/gaussian_accelerated_billiard_walk.hpp index a44608fb2..fbf43f443 100644 --- a/include/random_walks/gaussian_accelerated_billiard_walk.hpp +++ b/include/random_walks/gaussian_accelerated_billiard_walk.hpp @@ -68,7 +68,7 @@ struct GaussianAcceleratedBilliardWalk typedef typename Point::FT NT; template - Walk(GenericPolytope const& P, + Walk(GenericPolytope& P, Point const& p, Ellipsoid const& E, // ellipsoid representing the Gaussian distribution RandomNumberGenerator &rng) @@ -83,7 +83,7 @@ struct GaussianAcceleratedBilliardWalk } template - Walk(GenericPolytope const& P, + Walk(GenericPolytope& P, Point const& p, Ellipsoid const& E, // ellipsoid representing the Gaussian distribution RandomNumberGenerator &rng, @@ -104,7 +104,7 @@ struct GaussianAcceleratedBilliardWalk typename GenericPolytope, typename Ellipsoid > - inline void apply(GenericPolytope const& P, + inline void apply(GenericPolytope& P, Point &p, // a point to return the result Ellipsoid const& E, // ellipsoid representing the Gaussian distribution unsigned int const& walk_length, @@ -181,7 +181,7 @@ struct GaussianAcceleratedBilliardWalk typename GenericPolytope, typename Ellipsoid > - inline void initialize(GenericPolytope const& P, + inline void initialize(GenericPolytope& P, Point const& p, // a point to start Ellipsoid const& E, // ellipsoid representing the Gaussian distribution RandomNumberGenerator &rng) diff --git a/include/random_walks/gaussian_ball_walk.hpp b/include/random_walks/gaussian_ball_walk.hpp index c641b7344..8c267e0f9 100644 --- a/include/random_walks/gaussian_ball_walk.hpp +++ b/include/random_walks/gaussian_ball_walk.hpp @@ -46,19 +46,19 @@ struct Walk typedef typename Point::FT NT; template - static inline NT compute_delta(GenericPolytope const& P, NT const& a) + static inline NT compute_delta(GenericPolytope& P, NT const& a) { //return ((P.InnerBall()).second * NT(4)) / NT(P.dimension()); return (NT(4) * (P.InnerBall()).second) / std::sqrt(std::max(NT(1), a) * NT(P.dimension())); } - Walk (Polytope const& P, Point const& p, NT const& a, + Walk (Polytope& P, Point const& p, NT const& a, RandomNumberGenerator &rng) { _delta = compute_delta(P, a); } - Walk (Polytope const& P, + Walk (Polytope& P, Point const& p, NT const& a, RandomNumberGenerator &rng, diff --git a/include/random_walks/gaussian_cdhr_walk.hpp b/include/random_walks/gaussian_cdhr_walk.hpp index 8962ce413..04ebedbc4 100644 --- a/include/random_walks/gaussian_cdhr_walk.hpp +++ b/include/random_walks/gaussian_cdhr_walk.hpp @@ -75,7 +75,7 @@ struct Walk typedef typename Polytope::PointType Point; typedef typename Point::FT NT; - Walk(Polytope const& P, + Walk(Polytope& P, Point const& p, NT const& a_i, RandomNumberGenerator &rng) @@ -83,7 +83,7 @@ struct Walk initialize(P, p, a_i, rng); } - Walk(Polytope const& P, + Walk(Polytope& P, Point const& p, NT const& a_i, RandomNumberGenerator& rng, diff --git a/include/random_walks/gaussian_hamiltonian_monte_carlo_exact_walk.hpp b/include/random_walks/gaussian_hamiltonian_monte_carlo_exact_walk.hpp index 954fda731..8b83b053b 100644 --- a/include/random_walks/gaussian_hamiltonian_monte_carlo_exact_walk.hpp +++ b/include/random_walks/gaussian_hamiltonian_monte_carlo_exact_walk.hpp @@ -19,7 +19,7 @@ struct GaussianHamiltonianMonteCarloExactWalk GaussianHamiltonianMonteCarloExactWalk(double L, unsigned int _rho) : param(L, true, _rho, true) {} - + GaussianHamiltonianMonteCarloExactWalk(double L) : param(L, true, 0, false) {} @@ -28,7 +28,7 @@ struct GaussianHamiltonianMonteCarloExactWalk : param(0, false, 0, false) {} - + struct parameters { parameters(double L, bool set, unsigned int _rho, bool _set_rho) @@ -80,7 +80,7 @@ struct Walk < typename GenericPolytope > - inline void apply(GenericPolytope const& P, + inline void apply(GenericPolytope& P, Point& p, NT const& a_i, unsigned int const& walk_length, @@ -120,7 +120,7 @@ struct Walk < typename GenericPolytope > - inline void get_starting_point(GenericPolytope const& P, + inline void get_starting_point(GenericPolytope& P, Point const& center, Point &q, unsigned int const& walk_length, @@ -141,7 +141,7 @@ struct Walk < typename GenericPolytope > - inline void parameters_burnin(GenericPolytope const& P, + inline void parameters_burnin(GenericPolytope& P, Point const& center, unsigned int const& num_points, unsigned int const& walk_length, @@ -154,7 +154,7 @@ struct Walk pointset.push_back(_p); NT rad = NT(0), max_dist, Lmax = NT(0), radius = P.InnerBall().second; - for (int i = 0; i < num_points; i++) + for (int i = 0; i < num_points; i++) { p = GetPointInDsphere::apply(n, radius, rng); p += center; @@ -162,18 +162,18 @@ struct Walk apply(P, p, walk_length, rng); max_dist = get_max_distance(pointset, p, rad); - if (max_dist > Lmax) + if (max_dist > Lmax) { Lmax = max_dist; } - if (2.0*rad > Lmax) + if (2.0*rad > Lmax) { Lmax = 2.0 * rad; } pointset.push_back(p); } - if (Lmax > _Len) + if (Lmax > _Len) { update_delta(Lmax); } @@ -191,7 +191,7 @@ private : < typename GenericPolytope > - inline void initialize(GenericPolytope const& P, + inline void initialize(GenericPolytope& P, Point const& p, NT const& a_i, RandomNumberGenerator &rng) @@ -239,14 +239,14 @@ private : p.set_coord(i, C * std::cos(omega * T + Phi)); v.set_coord(i, -C * omega * std::sin(omega * T + Phi)); } - + } - inline double get_max_distance(std::vector &pointset, Point const& q, double &rad) + inline double get_max_distance(std::vector &pointset, Point const& q, double &rad) { double dis = -1.0, temp_dis; int jj = 0; - for (auto vecit = pointset.begin(); vecit!=pointset.end(); vecit++, jj++) + for (auto vecit = pointset.begin(); vecit!=pointset.end(); vecit++, jj++) { temp_dis = (q.getCoefficients() - (*vecit).getCoefficients()).norm(); if (temp_dis > dis) { diff --git a/include/random_walks/gaussian_rdhr_walk.hpp b/include/random_walks/gaussian_rdhr_walk.hpp index de7fd7bf9..b7a53abe7 100644 --- a/include/random_walks/gaussian_rdhr_walk.hpp +++ b/include/random_walks/gaussian_rdhr_walk.hpp @@ -80,10 +80,10 @@ struct Walk typedef typename Polytope::PointType Point; typedef typename Point::FT NT; - Walk(Polytope const&, Point const&, NT const&, RandomNumberGenerator&) + Walk(Polytope&, Point const&, NT const&, RandomNumberGenerator&) {} - Walk(Polytope const&, Point const&, NT const&, RandomNumberGenerator&, + Walk(Polytope&, Point const&, NT const&, RandomNumberGenerator&, parameters&) {} diff --git a/include/random_walks/multithread_walks.hpp b/include/random_walks/multithread_walks.hpp index 45b2b67cb..c42fba1fa 100644 --- a/include/random_walks/multithread_walks.hpp +++ b/include/random_walks/multithread_walks.hpp @@ -58,7 +58,7 @@ struct BCDHRWalk_multithread //typedef thread_params thread_parameters_; template - Walk(GenericPolytope const& P, thread_parameters_ ¶meters, RandomNumberGenerator& rng) + Walk(GenericPolytope& P, thread_parameters_ ¶meters, RandomNumberGenerator& rng) { initialize(P, parameters, rng); } @@ -68,7 +68,7 @@ struct BCDHRWalk_multithread typename BallPolytope > inline void apply(BallPolytope const& P, - thread_parameters_ ¶ms, // parameters + thread_parameters_ ¶ms, // parameters unsigned int const& walk_length, RandomNumberGenerator& rng) { @@ -97,13 +97,13 @@ struct BCDHRWalk_multithread template inline void initialize(GenericBody const& P, - thread_parameters_ ¶ms, // parameters + thread_parameters_ ¶ms, // parameters RandomNumberGenerator& rng) { params.lambdas.setZero(P.num_of_hyperplanes()); params.rand_coord = rng.sample_uidist(); NT kapa = rng.sample_urdist(); - + std::pair bpair = P.line_intersect_coord(params.p, params.rand_coord, params.lambdas); params.p_prev = params.p; @@ -158,7 +158,7 @@ struct BRDHRWalk_multithread //typedef thread_params thread_parameters_; template - Walk(GenericPolytope const& P, thread_parameters_ ¶meters, RandomNumberGenerator& rng) + Walk(GenericPolytope& P, thread_parameters_ ¶meters, RandomNumberGenerator& rng) { initialize(P, parameters, rng); } @@ -168,7 +168,7 @@ struct BRDHRWalk_multithread typename BallPolytope > inline void apply(BallPolytope const& P, - thread_parameters_ ¶ms, // parameters + thread_parameters_ ¶ms, // parameters unsigned int const& walk_length, RandomNumberGenerator& rng) { @@ -191,7 +191,7 @@ struct BRDHRWalk_multithread template inline void initialize(GenericBody const& P, - thread_parameters_ ¶ms, // parameters + thread_parameters_ ¶ms, // parameters RandomNumberGenerator& rng) { params.lambdas.setZero(P.num_of_hyperplanes()); @@ -243,7 +243,7 @@ struct Walk typedef thread_parameters thread_parameters_; //typedef thread_params thread_parameters_; - Walk(Polytope const& P, + Walk(Polytope& P, thread_parameters_ ¶ms, NT const& a_i, RandomNumberGenerator &rng) @@ -252,7 +252,7 @@ struct Walk } template - Walk(Polytope const& P, + Walk(Polytope& P, thread_parameters_ ¶ms, NT const& a_i, RandomNumberGenerator &rng, @@ -260,14 +260,14 @@ struct Walk { initialize(P, params, a_i, rng); } - + template < typename BallPolytope > inline void apply(BallPolytope const& P, - thread_parameters_ ¶ms, // parameters + thread_parameters_ ¶ms, // parameters NT const& a_i, unsigned int const& walk_length, RandomNumberGenerator &rng) @@ -293,7 +293,7 @@ private : template inline void initialize(BallPolytope const& P, - thread_parameters_ ¶ms, // parameters + thread_parameters_ ¶ms, // parameters NT const& a_i, RandomNumberGenerator &rng) { @@ -345,11 +345,11 @@ struct Walk typedef thread_parameters thread_parameters_; //typedef thread_params thread_parameters_; - Walk(Polytope const&, thread_parameters_ &, NT const&, RandomNumberGenerator&) + Walk(Polytope&, thread_parameters_ &, NT const&, RandomNumberGenerator&) {} template - Walk(Polytope const&, thread_parameters_ &, NT const&, RandomNumberGenerator&, + Walk(Polytope&, thread_parameters_ &, NT const&, RandomNumberGenerator&, parameters&) {} @@ -358,7 +358,7 @@ struct Walk typename BallPolytope > inline void apply(BallPolytope const& P, - thread_parameters_ ¶ms, // parameters + thread_parameters_ ¶ms, // parameters NT const& a_i, unsigned int const& walk_length, RandomNumberGenerator &rng) @@ -440,7 +440,7 @@ struct Walk //typedef thread_params thread_parameters_; template - Walk(GenericPolytope const& P, thread_parameters_ ¶meters, RandomNumberGenerator &rng) + Walk(GenericPolytope& P, thread_parameters_ ¶meters, RandomNumberGenerator &rng) { _Len = compute_diameter ::template compute(P); @@ -448,7 +448,7 @@ struct Walk } template - Walk(GenericPolytope const& P, thread_parameters_ ¶meters, RandomNumberGenerator &rng, + Walk(GenericPolytope& P, thread_parameters_ ¶meters, RandomNumberGenerator &rng, parameters_ const& params) { _Len = params.set_L ? params.m_L @@ -461,7 +461,7 @@ struct Walk < typename GenericPolytope > - inline void apply(GenericPolytope const& P, + inline void apply(GenericPolytope& P, thread_parameters_ ¶meters, unsigned int const& walk_length, RandomNumberGenerator &rng) @@ -491,7 +491,7 @@ struct Walk P.compute_reflection(parameters.v, parameters.p, pbpair.second); it++; } - if (it == 50*n) + if (it == 50*n) { parameters.p = parameters.p0; } @@ -509,7 +509,7 @@ private : < typename GenericPolytope > - inline void initialize(GenericPolytope const& P, + inline void initialize(GenericPolytope& P, thread_parameters_ ¶meters, RandomNumberGenerator &rng) { @@ -524,7 +524,7 @@ private : std::pair pbpair = P.line_positive_intersect(parameters.p, parameters.v, parameters.lambdas, parameters.Av); - if (T <= pbpair.first) + if (T <= pbpair.first) { parameters.p += (T * parameters.v); parameters.lambda_prev = T; @@ -538,9 +538,9 @@ private : while (it <= 50*n) { std::pair pbpair - = P.line_positive_intersect(parameters.p, parameters.v, parameters.lambdas, + = P.line_positive_intersect(parameters.p, parameters.v, parameters.lambdas, parameters.Av, parameters.lambda_prev); - if (T <= pbpair.first) + if (T <= pbpair.first) { parameters.p += (T * parameters.v); parameters.lambda_prev = T; @@ -599,7 +599,7 @@ struct Walk //typedef thread_params thread_parameters_; template - Walk(GenericPolytope const& P, thread_parameters_ ¶meters, RandomNumberGenerator& rng) + Walk(GenericPolytope& P, thread_parameters_ ¶meters, RandomNumberGenerator& rng) { initialize(P, parameters, rng); } @@ -610,7 +610,7 @@ struct Walk typename BallPolytope > inline void apply(BallPolytope const& P, - thread_parameters_ ¶ms, // parameters + thread_parameters_ ¶ms, // parameters unsigned int const& walk_length, RandomNumberGenerator &rng) { @@ -634,7 +634,7 @@ private : template inline void initialize(BallPolytope const& P, - thread_parameters_ ¶ms, // parameters + thread_parameters_ ¶ms, // parameters RandomNumberGenerator &rng) { params.lambdas.setZero(P.num_of_hyperplanes()); @@ -690,7 +690,7 @@ struct Walk //typedef thread_params thread_parameters_; template - Walk(GenericPolytope const& P, thread_parameters_ ¶meters, RandomNumberGenerator& rng) + Walk(GenericPolytope& P, thread_parameters_ ¶meters, RandomNumberGenerator& rng) { initialize(P, parameters, rng); } @@ -700,7 +700,7 @@ struct Walk typename BallPolytope > inline void apply(BallPolytope const& P, - thread_parameters_ ¶ms, // parameters + thread_parameters_ ¶ms, // parameters unsigned int const& walk_length, RandomNumberGenerator& rng) { @@ -719,7 +719,7 @@ private : template inline void initialize(BallPolytope const& P, - thread_parameters_ ¶ms, // parameters + thread_parameters_ ¶ms, // parameters RandomNumberGenerator &rng) { params.lambdas.setZero(P.num_of_hyperplanes()); diff --git a/include/random_walks/uniform_ball_walk.hpp b/include/random_walks/uniform_ball_walk.hpp index aeee06537..77c608b72 100644 --- a/include/random_walks/uniform_ball_walk.hpp +++ b/include/random_walks/uniform_ball_walk.hpp @@ -46,14 +46,14 @@ struct BallWalk typedef typename Point::FT NT; template - Walk(GenericPolytope const& P, Point const& /*p*/, + Walk(GenericPolytope& P, Point const& /*p*/, RandomNumberGenerator& /*rng*/) { _delta = compute_delta(P); } template - Walk(GenericPolytope const& P, Point const& /*p*/, + Walk(GenericPolytope& P, Point const& /*p*/, RandomNumberGenerator& /*rng*/, parameters const& params) { _delta = params.set_delta ? params.m_L @@ -61,7 +61,7 @@ struct BallWalk } template - static inline NT compute_delta(GenericPolytope const& P) + static inline NT compute_delta(GenericPolytope& P) { //return ((P.InnerBall()).second * NT(4)) / NT(P.dimension()); return (NT(4) * (P.InnerBall()).second) / std::sqrt(NT(P.dimension())); diff --git a/include/random_walks/uniform_cdhr_walk.hpp b/include/random_walks/uniform_cdhr_walk.hpp index b1a1a5386..12d2ff78e 100644 --- a/include/random_walks/uniform_cdhr_walk.hpp +++ b/include/random_walks/uniform_cdhr_walk.hpp @@ -30,13 +30,13 @@ struct Walk typedef typename Point::FT NT; template - Walk(GenericPolytope const& P, Point const& p, RandomNumberGenerator& rng) + Walk(GenericPolytope& P, Point const& p, RandomNumberGenerator& rng) { initialize(P, p, rng); } template - Walk(GenericPolytope const& P, Point const& p, + Walk(GenericPolytope& P, Point const& p, RandomNumberGenerator& rng, parameters const& params) { initialize(P, p, rng); diff --git a/include/random_walks/uniform_rdhr_walk.hpp b/include/random_walks/uniform_rdhr_walk.hpp index a322fe12c..5e0eb4750 100644 --- a/include/random_walks/uniform_rdhr_walk.hpp +++ b/include/random_walks/uniform_rdhr_walk.hpp @@ -31,13 +31,13 @@ struct Walk typedef typename Point::FT NT; template - Walk(GenericPolytope const& P, Point const& p, RandomNumberGenerator& rng) + Walk(GenericPolytope& P, Point const& p, RandomNumberGenerator& rng) { initialize(P, p, rng); } template - Walk(GenericPolytope const& P, Point const& p, + Walk(GenericPolytope& P, Point const& p, RandomNumberGenerator& rng, parameters const& params) { initialize(P, p, rng); @@ -47,7 +47,7 @@ struct Walk < typename BallPolytope > - inline void apply(BallPolytope const& P, + inline void apply(BallPolytope& P, Point& p, // a point to start unsigned int const& walk_length, RandomNumberGenerator& rng) @@ -67,7 +67,7 @@ struct Walk private : template - inline void initialize(BallPolytope const& P, + inline void initialize(BallPolytope& P, Point const& p, RandomNumberGenerator &rng) { diff --git a/include/sampling/random_point_generators.hpp b/include/sampling/random_point_generators.hpp index abc7677e7..86b10666c 100644 --- a/include/sampling/random_point_generators.hpp +++ b/include/sampling/random_point_generators.hpp @@ -143,7 +143,7 @@ struct GaussianRandomPointGenerator typename WalkPolicy, typename RandomNumberGenerator > - static void apply(Polytope const& P, + static void apply(Polytope& P, Point &p, // a point to start NT const& a_i, unsigned int const& rnum, @@ -170,7 +170,7 @@ struct GaussianRandomPointGenerator typename RandomNumberGenerator, typename Parameters > - static void apply(Polytope const& P, + static void apply(Polytope& P, Point &p, // a point to start NT const& a_i, unsigned int const& rnum, @@ -203,7 +203,7 @@ struct BoundaryRandomPointGenerator typename WalkPolicy, typename RandomNumberGenerator > - static void apply(Polytope const& P, + static void apply(Polytope& P, Point &p, // a point to start unsigned int const& rnum, unsigned int const& walk_length, @@ -282,7 +282,7 @@ struct ExponentialRandomPointGenerator typename WalkPolicy, typename RandomNumberGenerator > - static void apply(Polytope const& P, + static void apply(Polytope& P, Point &p, // a point to start Point const& c, // bias function NT const& T, // temperature/variance @@ -315,7 +315,7 @@ struct ExponentialRandomPointGenerator typename RandomNumberGenerator, typename Parameters > - static void apply(Polytope const& P, + static void apply(Polytope& P, Point &p, // a point to start Point const& c, // bias function NT const& T, // temperature/variance diff --git a/include/volume/volume_cooling_balls.hpp b/include/volume/volume_cooling_balls.hpp index 29731a2e9..d90604fa4 100644 --- a/include/volume/volume_cooling_balls.hpp +++ b/include/volume/volume_cooling_balls.hpp @@ -694,7 +694,7 @@ template typename RandomNumberGenerator = BoostRandomNumberGenerator > -std::pair volume_cooling_balls(Polytope const& Pin, +std::pair volume_cooling_balls(Polytope& Pin, RandomNumberGenerator &rng, double const& error = 0.1, unsigned int const& walk_length = 1, diff --git a/include/volume/volume_cooling_gaussians.hpp b/include/volume/volume_cooling_gaussians.hpp index ef7ab0f70..ca06ce315 100644 --- a/include/volume/volume_cooling_gaussians.hpp +++ b/include/volume/volume_cooling_gaussians.hpp @@ -57,7 +57,7 @@ struct update_delta> // Compute the first variance a_0 for the starting gaussian template -void get_first_gaussian(Polytope const& P, +void get_first_gaussian(Polytope& P, NT const& frac, NT const& chebychev_radius, NT const& error, @@ -125,7 +125,7 @@ template typename NT, typename RandomNumberGenerator > -NT get_next_gaussian(Polytope const& P, +NT get_next_gaussian(Polytope& P, Point &p, NT const& a, const unsigned int &N, @@ -186,7 +186,7 @@ template typename NT, typename RandomNumberGenerator > -void compute_annealing_schedule(Polytope const& P, +void compute_annealing_schedule(Polytope& P, NT const& ratio, NT const& C, NT const& frac, @@ -289,7 +289,7 @@ template typename RandomNumberGenerator > -double volume_cooling_gaussians(Polytope const& Pin, +double volume_cooling_gaussians(Polytope& Pin, RandomNumberGenerator& rng, double const& error = 0.1, unsigned int const& walk_length = 1) @@ -483,7 +483,7 @@ double volume_cooling_gaussians(Polytope &Pin, { RandomNumberGenerator rng(Pin.dimension()); Pin.set_interior_point(interior_point); - + return volume_cooling_gaussians(Pin, rng, error, walk_length); } diff --git a/include/volume/volume_cooling_hpoly.hpp b/include/volume/volume_cooling_hpoly.hpp index 1175d9b64..c8183384c 100644 --- a/include/volume/volume_cooling_hpoly.hpp +++ b/include/volume/volume_cooling_hpoly.hpp @@ -135,7 +135,7 @@ bool get_next_zonoball(std::vector &HPolySet, return false; } -template +template < typename RandomPointGenerator, typename ZonoHP, @@ -374,7 +374,7 @@ template typename HPolytope, typename Polytope > -double volume_cooling_hpoly(Polytope const& Pin, +double volume_cooling_hpoly(Polytope& Pin, double const& error = 0.1, unsigned int const& walk_length = 1) { diff --git a/include/volume/volume_sequence_of_balls.hpp b/include/volume/volume_sequence_of_balls.hpp index fc1342cee..b79358a6e 100644 --- a/include/volume/volume_sequence_of_balls.hpp +++ b/include/volume/volume_sequence_of_balls.hpp @@ -44,7 +44,7 @@ template typename RandomNumberGenerator > -double volume_sequence_of_balls(Polytope const& Pin, +double volume_sequence_of_balls(Polytope& Pin, RandomNumberGenerator &rng, double const& error = 1.0, unsigned int const& walk_length = 1, @@ -258,7 +258,7 @@ double volume_sequence_of_balls(Polytope &Pin, { RandomNumberGenerator rng(Pin.dimension()); Pin.set_interior_point(interior_point); - + return volume_sequence_of_balls(Pin, rng, error, walk_length, n_threads); } From 553cf553a1f3e313aee315bf4e5d347c4bf469df Mon Sep 17 00:00:00 2001 From: Vissarion Fisikopoulos Date: Mon, 13 Feb 2023 15:05:55 +0200 Subject: [PATCH 19/20] Fix ambiguous call to fix function by renaming volesti's diagnostic function. (#263) --- include/diagnostics/raftery.hpp | 13 ++++++------- .../diagnostics/raftery_subroutines/empquant.hpp | 4 ++-- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/include/diagnostics/raftery.hpp b/include/diagnostics/raftery.hpp index de7928202..1fa087a5d 100644 --- a/include/diagnostics/raftery.hpp +++ b/include/diagnostics/raftery.hpp @@ -29,10 +29,9 @@ #define DIAGNOSTICS_RAFTERY_HPP template -NT fix(NT x) +NT round_to_zero(NT x) { - if (x > 0.0) return std::floor(x); - return std::ceil(x); + return (x > 0.0) ? std::floor(x) : std::ceil(x); } #include "raftery_subroutines/empquant.hpp" @@ -121,13 +120,13 @@ MT perform_raftery(MT const& samples, NT const& q, NT const& r, NT const& s) NT psum = alpha + beta; NT tmp1 = std::log(psum * epss / std::max(alpha, beta)) / std::log(std::abs(1.0 - psum)); - NT nburn = fix((tmp1 + 1.0) * NT(kthin)); + NT nburn = round_to_zero((tmp1 + 1.0) * NT(kthin)); NT phi = ppnd((s + 1.0) / 2.0); NT tmp2 = (2.0 - psum) * alpha * beta * (phi * phi) / (psum * psum * psum * (r * r)); - NT nprec = fix(tmp2 + 1.0) * kthin; - NT nmin = fix(((1.0 - q) * q * (phi * phi) / (r * r)) + 1.0); + NT nprec = round_to_zero(tmp2 + 1.0) * kthin; + NT nmin = round_to_zero(((1.0 - q) * q * (phi * phi) / (r * r)) + 1.0); NT irl = (nburn + nprec) / nmin; - NT kind = std::max(fix(irl + 1.0), NT(kmind)); + NT kind = std::max(round_to_zero(irl + 1.0), NT(kmind)); results(i, 0) = NT(kthin); results(i, 1) = NT(nburn); diff --git a/include/diagnostics/raftery_subroutines/empquant.hpp b/include/diagnostics/raftery_subroutines/empquant.hpp index cd305372e..6604f0ad7 100644 --- a/include/diagnostics/raftery_subroutines/empquant.hpp +++ b/include/diagnostics/raftery_subroutines/empquant.hpp @@ -17,10 +17,10 @@ template NT empquant(VT const& sorted_samples, NT const& q) { unsigned int n = sorted_samples.rows(); - + NT order = (n - 1) * q + 1.0; NT fract = order - NT(int(order)); - int low = std::max(fix(order), 1.0); + int low = std::max(round_to_zero(order), 1.0); int high = std::min(low + 1.0, NT(n)); NT y = (1.0 - fract) * sorted_samples(low - 1) + fract * sorted_samples(high - 1); From 9d495d6768de9b0f5ddc24698bc99b29f8da1b78 Mon Sep 17 00:00:00 2001 From: Soumya Tarafder <63846042+Soumya624@users.noreply.github.com> Date: Mon, 20 Feb 2023 19:25:16 +0530 Subject: [PATCH 20/20] Updating documentation (#261) Adding WSL and MKL build instructions. --- CONTRIBUTING.md | 103 ++++++++++++++++---------------- docs/getting_started/install.md | 15 +++++ 2 files changed, 68 insertions(+), 50 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5d2414da9..3af68ab7b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,42 +2,42 @@ :+1::tada: First off, thanks for taking the time to contribute! :tada::+1: -The following is a set of guidelines for contributing to volesti, -which are hosted in the [GeomScale Organization](https://github.com/GeomScale) on GitHub. -These are mostly guidelines, not rules. +The following is a set of guidelines for contributing to volesti, +which are hosted in the [GeomScale Organization](https://github.com/GeomScale) on GitHub. +These are mostly guidelines, not rules. Use your best judgment, and feel free to propose changes to this document in a pull request. ## Table of Contents - * [Prerequisites (how to start)](#prerequisites--how-to-start-) - * [Testing the development branch of volesti (get the tools ready)](#testing-the-development-branch-of-volesti--get-the-tools-ready-) - * [Fork volesti repository (this is your repo now!)](#fork--volesti-repository--this-is-your-repo-now--) - + [Verify if your fork works (optional)](#verify-if-your-fork-works--optional-) - * [Working with volesti (get ready to contribute)](#working-with-volesti--get-ready-to-contribute-) - + [GitFlow workflow](#gitflow-workflow) - + [Create new branch for your work](#create-new-branch-for-your-work) - + [Verify your new branch (optional)](#verify-your-new-branch--optional-) - * [Modify the branch (implement, implement, implement)](#modify-the-branch--implement--implement--implement-) - + [Tests](#tests) - + [Push](#push) - * [Pull request (the joy of sharing)](#pull-request--the-joy-of-sharing-) - * [Review (ok this is not an exam)](#review--ok-this-is-not-an-exam-) - +- [Prerequisites (how to start)](#prerequisites--how-to-start-) +- [Testing the development branch of volesti (get the tools ready)](#testing-the-development-branch-of-volesti--get-the-tools-ready-) +- [Fork volesti repository (this is your repo now!)](#fork--volesti-repository--this-is-your-repo-now--) + - [Verify if your fork works (optional)](#verify-if-your-fork-works--optional-) +- [Working with volesti (get ready to contribute)](#working-with-volesti--get-ready-to-contribute-) + - [GitFlow workflow](#gitflow-workflow) + - [Create new branch for your work](#create-new-branch-for-your-work) + - [Verify your new branch (optional)](#verify-your-new-branch--optional-) +- [Modify the branch (implement, implement, implement)](#modify-the-branch--implement--implement--implement-) + - [Tests](#tests) + - [Push](#push) +- [Pull request (the joy of sharing)](#pull-request--the-joy-of-sharing-) +- [Review (ok this is not an exam)](#review--ok-this-is-not-an-exam-) + ## Prerequisites (how to start) -* git (see [Getting Started with Git](https://help.github.com/en/github/using-git/getting-started-with-git-and-github)) -* a compiler to run tests - gcc, clang, etc. -* configured GitHub account - +- git (see [Getting Started with Git](https://help.github.com/en/github/using-git/getting-started-with-git-and-github)) +- a compiler to run tests - gcc, clang, etc. +- configured GitHub account + Other helpful links: -* http://git-scm.com/documentation -* https://help.github.com/articles/set-up-git -* https://opensource.com/article/18/1/step-step-guide-git +- http://git-scm.com/documentation +- https://help.github.com/articles/set-up-git +- https://opensource.com/article/18/1/step-step-guide-git ## Testing the development branch of volesti (get the tools ready) -Clone the repository, +Clone the repository, git clone git@github.com:GeomScale/volume_approximation.git volesti cd volesti @@ -52,12 +52,14 @@ To compile the `C++` code you have to specify the path to external library `libl # e.g. on linux: cmake -DLP_SOLVE=/usr/lib/lp_solve/liblpsolve55.so .. make -Run the tests, +You can check [here](/docs/getting_started/install.md) to see more installation guide. - ctest -jK +Run the tests, -where `K` is the number of CPU threads. By adding the option `--verbose` to `ctest` you get more information about the tests, -*e.g.* time per test, volume computed and the name of the polytope or convex body. + ctest -jK + +where `K` is the number of CPU threads. By adding the option `--verbose` to `ctest` you get more information about the tests, +_e.g._ time per test, volume computed and the name of the polytope or convex body. ![test_cube](https://user-images.githubusercontent.com/3660366/72348403-0524df00-36e3-11ea-9b6d-288a2bddc22c.png) @@ -65,8 +67,8 @@ If everything works for you, you may move forward. ## Fork volesti repository (this is your repo now!) -You can't work directly in the original volesti repository, therefore you should create your fork of this library. -This way you can modify the code and when the job is done send a pull request to merge your changes with the original +You can't work directly in the original volesti repository, therefore you should create your fork of this library. +This way you can modify the code and when the job is done send a pull request to merge your changes with the original repository. ![fork](https://user-images.githubusercontent.com/3660366/72348562-57fe9680-36e3-11ea-9746-385ff61c752a.png) @@ -90,9 +92,10 @@ clone your repository and checkout develop branch git clone git@github.com:vissarion/volume_approximation.git volesti_fork cd volesti_fork - git checkout develop + git remote add upstream git@github.com:GeomScale/volesti.git + git fetch upstream + git checkout upstream/develop git branch -vv - git pull see commits @@ -105,17 +108,17 @@ For now you should see exactly the same commits as in `volesti` repository. ### GitFlow workflow -Volesit is using the [GitFlow](http://nvie.com/posts/a-successful-git-branching-model/) workflow. -It's because it is very well suited to collaboration and scaling the development team. +Volesit is using the [GitFlow](http://nvie.com/posts/a-successful-git-branching-model/) workflow. +It's because it is very well suited to collaboration and scaling the development team. Each repository using this model should contain two main branches: -* master - release-ready version of the library -* develop - development version of the library - -and could contain various supporting branches for new features and hotfixes. +- master - release-ready version of the library +- develop - development version of the library + +and could contain various supporting branches for new features and hotfixes. -As a contributor you'll most likely be adding new features or fixing bugs in the development version of the library. -This means that for each contribution you should create a new branch originating from the develop branch, +As a contributor you'll most likely be adding new features or fixing bugs in the development version of the library. +This means that for each contribution you should create a new branch originating from the develop branch, modify it and send a pull request in order to merge it, again with the develop branch. ### Create new branch for your work @@ -128,7 +131,7 @@ you should see ![branch -vv](https://user-images.githubusercontent.com/3660366/72348696-a1e77c80-36e3-11ea-93ec-70f5622c0675.png) -Now you should pick a name for your new branch that doesn't already exist. +Now you should pick a name for your new branch that doesn't already exist. The following checks for existing remote branches git branch -a @@ -136,7 +139,7 @@ The following checks for existing remote branches ![List of branches](https://user-images.githubusercontent.com/3660366/72348763-c5aac280-36e3-11ea-8f2c-c66e2c107929.png) Alternatively, you can check them on `GitHub`. -Assume you want to add some new functionality (i.e. a new feature) for example a new sampling algorithm. Then you have +Assume you want to add some new functionality (i.e. a new feature) for example a new sampling algorithm. Then you have to create a new branch e.g. `feature/the_fastest_sampling_algo_ever` Create new local branch @@ -168,12 +171,12 @@ Alternatively, your newly created remote branch is also available on GitHub ## Modify the branch (implement, implement, implement) -Before contributiong to a library by adding a new feature, or a bugfix, or improving documentation, +Before contributiong to a library by adding a new feature, or a bugfix, or improving documentation, it is always wise to interact with the community of developers, for example by opening an issue. ### Tests -Tests are placed in the `test` directory and use the [doctest](https://github.com/onqtam/doctest) library. +Tests are placed in the `test` directory and use the [doctest](https://github.com/onqtam/doctest) library. It is recommended to add new test whenever you contribute a new functionality/feature. Also if your contribution is a bugfix then consider adding this case to the test-suite. @@ -202,16 +205,16 @@ and click the "Create pull request" button. ## Review (ok this is not an exam) -After creating a pull request your code will be reviewed. You can propose one or more reviewers +After creating a pull request your code will be reviewed. You can propose one or more reviewers by clicking on the "Reviewers" button ![reviewer](https://user-images.githubusercontent.com/3660366/72349476-44ecc600-36e5-11ea-81cd-d0938d923529.png) -If there are no objections your changes will be merged. +If there are no objections your changes will be merged. Otherwise you'll see some comments under the pull request and/or under specific lines of your code. -Then you have to make the required changes, commit them and push to your branch. -Those changes will automatically be a part of the same pull request. This procedure will be repeated until the code +Then you have to make the required changes, commit them and push to your branch. +Those changes will automatically be a part of the same pull request. This procedure will be repeated until the code is ready for merging. -If you're curious how it looks like you may see one of the open or closed +If you're curious how it looks like you may see one of the open or closed [pull requests](https://github.com/GeomScale/volume_approximation/pulls). diff --git a/docs/getting_started/install.md b/docs/getting_started/install.md index 57962f8ff..cfdb773e7 100644 --- a/docs/getting_started/install.md +++ b/docs/getting_started/install.md @@ -17,6 +17,21 @@ make ``` For example: `-DLP_SOLVE=/usr/lib/lpsolve/liblpsolve55.so` +In WSL (Windows Subsystem Linux), you can run the following command to install libc6-dev-i386. This will be required for `ieeefp.h` which is used by `qd` library, + + sudo apt-get install libc6-dev-i386 + +Also to install `mkl` related dependencies, run the following, + + wget https://apt.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS-2023.PUB + sudo apt-key add GPG-PUB-KEY-INTEL-SW-PRODUCTS-2023.PUB + sudo sh -c 'echo deb https://apt.repos.intel.com/mkl all main > /etc/apt/sources.list.d/intel-mkl.list' + sudo apt-get update + sudo apt-get install intel-mkl-2020.4-912 + sudo sh -c "echo /opt/intel/mkl/lib/intel64 > /etc/ld.so.conf.d/intel-mkl.conf" + sudo ldconfig + export CPLUS_INCLUDE_PATH="/opt/intel/mkl/include:$CPLUS_INCLUDE_PATH" + You can run the tests by `cmake test` or `ctest -jK` where `K` the number of `CPU` threads. By adding the option `--verbose` to `ctest` you get more information about the tests, *e.g.* time per test, volume computed and the name of the polytope or convex body. ### Development environment from Docker container